Python Django管理中的默认过滤器
如何从“全部”更改默认筛选器选项?我有一个名为Python Django管理中的默认过滤器,python,django,django-admin,Python,Django,Django Admin,如何从“全部”更改默认筛选器选项?我有一个名为status的字段,它有三个值:activate、pending和rejected。当我在Django admin中使用list\u filter时,默认情况下过滤器设置为'All',但我想在默认情况下将其设置为pending。请注意,如果您不想预先选择过滤器值,而是希望在将数据显示在admin中之前始终对其进行预筛选,则应覆盖ModelAdmin.queryset()方法。我知道这不是最好的解决方案,但我更改了管理模板第25行和第37行的index
status
的字段,它有三个值:activate
、pending
和rejected
。当我在Django admin中使用list\u filter
时,默认情况下过滤器设置为'All',但我想在默认情况下将其设置为pending。请注意,如果您不想预先选择过滤器值,而是希望在将数据显示在admin中之前始终对其进行预筛选,则应覆盖ModelAdmin.queryset()
方法。我知道这不是最好的解决方案,但我更改了管理模板第25行和第37行的index.html,如下所示:
class MyModelAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
25:
37:
接受了上面ha22109的答案,并通过比较HTTP\u REFERER
和PATH\u INFO
修改为允许选择“全部”
class MyModelAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])
if test[-1] and not test[-1].startswith('?'):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
def changelist_视图(self、request、extra_context=None):
默认过滤器=False
尝试:
ref=request.META['HTTP\u REFERER']
pinfo=request.META['PATH\u INFO']
qstr=参考拆分(pinfo)
如果len(qstr)<2:
默认过滤器=真
除:
默认过滤器=真
如果是默认的\u过滤器:
q=request.GET.copy()
q['registered\uuu exact']='1'
request.GET=q
request.META['QUERY_STRING']=request.GET.urlencode()
返回super(InterestAdmin,self).changelist\u视图(请求,额外上下文=额外上下文)
我必须进行修改才能使过滤正常工作。加载页面时,前面的解决方案对我有效。如果执行了“操作”,则过滤器返回“全部”,而不是我的默认设置。此解决方案使用默认筛选器加载admin change页面,但在页面上发生其他活动时,也会维护筛选器更改或当前筛选器。我并没有测试所有的情况,但实际上它可能会限制默认过滤器的设置只在页面加载时出现
def changelist_view(self, request, extra_context=None):
default_filter = False
try:
ref = request.META['HTTP_REFERER']
pinfo = request.META['PATH_INFO']
qstr = ref.split(pinfo)
querystr = request.META['QUERY_STRING']
# Check the QUERY_STRING value, otherwise when
# trying to filter the filter gets reset below
if querystr is None:
if len(qstr) < 2 or qstr[1] == '':
default_filter = True
except:
default_filter = True
if default_filter:
q = request.GET.copy()
q['registered__isnull'] = 'True'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyAdmin, self).changelist_view(request, extra_context=extra_context)
def changelist_视图(self、request、extra_context=None):
默认过滤器=False
尝试:
ref=request.META['HTTP\u REFERER']
pinfo=request.META['PATH\u INFO']
qstr=参考拆分(pinfo)
querystr=request.META['QUERY\u STRING']
#检查查询字符串值,否则在
#尝试筛选筛选器将在下面重置
如果querystr为None:
如果len(qstr)<2或qstr[1]='':
默认过滤器=真
除:
默认过滤器=真
如果是默认的\u过滤器:
q=request.GET.copy()
q['registered\uuu isnull']='True'
request.GET=q
request.META['QUERY_STRING']=request.GET.urlencode()
返回super(MyAdmin,self).changelist\u视图(请求,额外上下文=额外上下文)
为了实现这一点,并在侧边栏中有一个可用的“全部”链接(即显示全部而不是显示挂起的链接),您需要创建一个自定义列表筛选器,继承自django.contrib.admin.filters.SimpleListFilter
,默认情况下在“挂起”上进行筛选。按照这些思路应该可以做到:
from datetime import date
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
class StatusFilter(SimpleListFilter):
title = _('Status')
parameter_name = 'status'
def lookups(self, request, model_admin):
return (
(None, _('Pending')),
('activate', _('Activate')),
('rejected', _('Rejected')),
('all', _('All')),
)
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() in ('activate', 'rejected'):
return queryset.filter(status=self.value())
elif self.value() == None:
return queryset.filter(status='pending')
class Admin(admin.ModelAdmin):
list_filter = [StatusFilter]
编辑:需要Django 1.4(谢谢Simon)使用Django选项,Python>=2.5,当然,Django>=1.4,对Greg的答案稍加改进
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
class OrderStatusFilter(SimpleListFilter):
title = _('Status')
parameter_name = 'status__exact'
default_status = OrderStatuses.closed
def lookups(self, request, model_admin):
return (('all', _('All')),) + OrderStatuses.choices
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup if self.value() else lookup == self.default_status,
'query_string': cl.get_query_string({self.parameter_name: lookup}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() in OrderStatuses.values:
return queryset.filter(status=self.value())
elif self.value() is None:
return queryset.filter(status=self.default_status)
class Admin(admin.ModelAdmin):
list_filter = [OrderStatusFilter]
感谢Greg提供了很好的解决方案 我知道这个问题已经很老了,但它仍然有效。我相信这是最正确的方法。它本质上与Greg的方法相同,但被表述为易于重用的可扩展类
from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _
class DefaultListFilter(SimpleListFilter):
all_value = '_all'
def default_value(self):
raise NotImplementedError()
def queryset(self, request, queryset):
if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
return queryset
if self.parameter_name in request.GET:
return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})
return queryset.filter(**{self.parameter_name:self.default_value()})
def choices(self, cl):
yield {
'selected': self.value() == self.all_value,
'query_string': cl.get_query_string({self.parameter_name: self.all_value}, []),
'display': _('All'),
}
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == force_text(lookup) or (self.value() == None and force_text(self.default_value()) == force_text(lookup)),
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
class StatusFilter(DefaultListFilter):
title = _('Status ')
parameter_name = 'status__exact'
def lookups(self, request, model_admin):
return ((0,'activate'), (1,'pending'), (2,'rejected'))
def default_value(self):
return 1
class MyModelAdmin(admin.ModelAdmin):
list_filter = (StatusFilter,)
有点离题,但我对一个类似问题的探索让我来到了这里。我希望有一个按日期的默认查询(即如果没有提供输入,则只显示带有
时间戳的对象,时间戳为'Today'),这使问题有点复杂。以下是我的想法:
from django.contrib.admin.options import IncorrectLookupParameters
from django.core.exceptions import ValidationError
class TodayDefaultDateFieldListFilter(admin.DateFieldListFilter):
""" If no date is query params are provided, query for Today """
def queryset(self, request, queryset):
try:
if not self.used_parameters:
now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
self.used_parameters = {
('%s__lt' % self.field_path): str(now + datetime.timedelta(days=1)),
('%s__gte' % self.field_path): str(now),
}
# Insure that the dropdown reflects 'Today'
self.date_params = self.used_parameters
return queryset.filter(**self.used_parameters)
except ValidationError, e:
raise IncorrectLookupParameters(e)
class ImagesAdmin(admin.ModelAdmin):
list_filter = (
('timestamp', TodayDefaultDateFieldListFilter),
)
这是对默认的DateFieldListFilter
的简单重写。通过设置self.date\u参数
,可以确保过滤器下拉列表将更新为与self.used\u参数
匹配的任何选项。因此,您必须确保self.used_参数
正是其中一个下拉选择所使用的参数(即,在使用“今天”或“过去7天”时,找出date_参数
,并构建self.used_参数
以匹配这些参数)
这是为配合Django 1.4.10而构建的,这是我使用重定向的通用解决方案,它只检查是否有任何GET参数,如果没有,则使用默认的GET参数重定向。我还有一个列表过滤器集,所以它会选择并显示默认值
from django.shortcuts import redirect
class MyModelAdmin(admin.ModelAdmin):
...
list_filter = ('status', )
def changelist_view(self, request, extra_context=None):
referrer = request.META.get('HTTP_REFERER', '')
get_param = "status__exact=5"
if len(request.GET) == 0 and '?' not in referrer:
return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
唯一需要注意的是,当您直接访问url中存在“?”的页面时,没有设置HTTP_REFERER,因此它将使用默认参数并重定向。这对我来说很好,当你点击管理过滤器的时候效果很好
更新:
为了绕过警告,我最终编写了一个自定义过滤器函数,简化了changelist\u视图功能。以下是过滤器:
class MyModelStatusFilter(admin.SimpleListFilter):
title = _('Status')
parameter_name = 'status'
def lookups(self, request, model_admin): # Available Values / Status Codes etc..
return (
(8, _('All')),
(0, _('Incomplete')),
(5, _('Pending')),
(6, _('Selected')),
(7, _('Accepted')),
)
def choices(self, cl): # Overwrite this method to prevent the default "All"
from django.utils.encoding import force_text
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == force_text(lookup),
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset): # Run the queryset based on your lookup values
if self.value() is None:
return queryset.filter(status=5)
elif int(self.value()) == 0:
return queryset.filter(status__lte=4)
elif int(self.value()) == 8:
return queryset.all()
elif int(self.value()) >= 5:
return queryset.filter(status=self.value())
return queryset.filter(status=5)
如果不存在,则changelist_视图现在只传递默认参数。其想法是通过不使用get参数来消除泛型过滤器查看所有内容的功能。要查看我为此指定的所有状态=8:
class MyModelAdmin(admin.ModelAdmin):
...
list_filter = ('status', )
def changelist_view(self, request, extra_context=None):
if len(request.GET) == 0:
get_param = "status=5"
return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
return super(MyModelAdmin, self).changelist_view(request, extra_context=extra_context)
这可能是一条老线索,但我想我会添加我的解决方案,因为我在谷歌搜索中找不到更好的答案
做什么(不确定它的Deminic Rodger或ha22109是否在ModelAdmin for changelist_视图中回答)
class MyModelAdmin(admin.ModelAdmin):
list_filter = (CustomFilter,)
def changelist_view(self, request, extra_context=None):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
然后我们需要创建一个自定义SimpleListFilter
class CustomFilter(admin.SimpleListFilter):
title = 'Decommissioned'
parameter_name = 'decommissioned' # i chose to change it
def lookups(self, request, model_admin):
return (
('All', 'all'),
('1', 'Decommissioned'),
('0', 'Active (or whatever)'),
)
# had to override so that we could remove the default 'All' option
# that won't work with our default filter in the ModelAdmin class
def choices(self, cl):
yield {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [self.parameter_name]),
# 'display': _('All'),
}
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() == '1':
return queryset.filter(decommissioned=1)
elif self.value() == '0':
return queryset.filter(decommissioned=0)
return queryset
from django.utils.encoding import force_text
def choices(self, changelist):
for lookup, title in self.lookup_choices:
yield {
'selected': force_text(self.value()) == force_text(lookup),
'query_string': changelist.get_query_string(
{self.parameter_name: lookup}, []
),
'display': title,
}
您可以简单地使用返回queryset.filter()
或如果self.value()为None
并重写SimpleListFilter的方法
class CustomFilter(admin.SimpleListFilter):
title = 'Decommissioned'
parameter_name = 'decommissioned' # i chose to change it
def lookups(self, request, model_admin):
return (
('All', 'all'),
('1', 'Decommissioned'),
('0', 'Active (or whatever)'),
)
# had to override so that we could remove the default 'All' option
# that won't work with our default filter in the ModelAdmin class
def choices(self, cl):
yield {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [self.parameter_name]),
# 'display': _('All'),
}
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() == '1':
return queryset.filter(decommissioned=1)
elif self.value() == '0':
return queryset.filter(decommissioned=0)
return queryset
from django.utils.encoding import force_text
def choices(self, changelist):
for lookup, title in self.lookup_choices:
yield {
'selected': force_text(self.value()) == force_text(lookup),
'query_string': changelist.get_query_string(
{self.parameter_name: lookup}, []
),
'display': title,
}
这是我能够生成的最干净版本的过滤器,它具有重新定义的“All”和选中的默认值
默认情况下,If显示当前发生的行程
class HappeningTripFilter(admin.SimpleListFilter):
"""
Filter the Trips Happening in the Past, Future or now.
"""
default_value = 'now'
title = 'Happening'
parameter_name = 'happening'
def lookups(self, request, model_admin):
"""
List the Choices available for this filter.
"""
return (
('all', 'All'),
('future', 'Not yet started'),
('now', 'Happening now'),
('past', 'Already finished'),
)
def choices(self, changelist):
"""
Overwrite this method to prevent the default "All".
"""
value = self.value() or self.default_value
for lookup, title in self.lookup_choices:
yield {
'selected': value == force_text(lookup),
'query_string': changelist.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
"""
Returns the Queryset depending on the Choice.
"""
value = self.value() or self.default_value
now = timezone.now()
if value == 'future':
return queryset.filter(start_date_time__gt=now)
if value == 'now':
return queryset.filter(start_date_time__lte=now, end_date_time__gte=now)
if value == 'past':
return queryset.filter(end_date_time__lt=now)
return queryset.all()
创建了一个可重用的Fil
from django.contrib import admin
from .models import SomeModelWithStatus
class StatusFilter(PreFilteredListFilter):
default_value = SomeModelWithStatus.Status.FOO
title = _('Status')
parameter_name = 'status'
def get_lookups(self):
return SomeModelWithStatus.Status.choices
@admin.register(SomeModelWithStatus)
class SomeModelAdmin(admin.ModelAdmin):
list_filter = (StatusFilter, )