Django admin 中的默认过滤器
Posted
技术标签:
【中文标题】Django admin 中的默认过滤器【英文标题】:Default filter in Django admin 【发布时间】:2010-10-25 11:55:51 【问题描述】:如何将默认过滤器选项从“全部”更改?我有一个名为status
的字段,它具有三个值:activate
、pending
和rejected
。当我在 Django admin 中使用 list_filter
时,过滤器默认设置为“全部”,但我想将其默认设置为挂起。
【问题讨论】:
【参考方案1】:为了实现这一点并且在您的侧边栏中有一个可用的“全部”链接(即显示全部而不是显示待处理的链接),您需要创建一个自定义列表过滤器,继承来自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 1.4,尽管现在应该已经给出了。 @Greg 你如何完全删除过滤器的功能和管理页面的过滤器标签? 嗯...docs.djangoproject.com/en/1.8/ref/contrib/admin/… 这个解决方案有一个小缺点。当过滤器为空时(实际使用“待处理”过滤器),如果 show_full_result_count 为 True(默认情况下),Django 1.8 会错误地确定完整结果计数并且不显示结果计数。 —— 请注意,如果您未能在解决方案中覆盖choices
方法,它会烦人地继续添加自己的 All 选项选择列表的顶部。【参考方案2】:
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)
【讨论】:
此解决方案的缺点是,虽然 UI 中仍显示“全部”选项,但选择它仍会应用默认过滤。 我有同样的问题,但我可以理解回放...对不起,我是 Django 的新手...但也许这会工作blog.dougalmatthews.com/2008/10/… 这很好,但我需要在 url 中查看 get 参数,以便我的过滤器可以选择它并显示它。很快发布我的解决方案。 缺少解释。仅仅发布一段代码可能对每个人都没有帮助。最重要的是它不起作用,没有一点上下文很难找出原因【参考方案3】:采用上面 ha22109 的答案并修改为允许通过比较 HTTP_REFERER
和 PATH_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)
【讨论】:
这对我来说很糟糕,因为 HTTP_REFERER 并不总是存在。我做了'referer = request.META.get('HTTP_REFERER', ''); test = referer.split(request.META['PATH_INFO'])` @Ben 我正在使用你的两行 referer = request.META.get('HTTP_REFERER', '') test = referer.split(request.META['PATH_INFO'])。我不太关心 HTTP_REFERER 。如果 HTTP_REFERER 不存在,问题是否从这些行中完全解决? @the_game 是的,这个想法是,如果您使用方括号尝试访问不存在的密钥,它会抛出KeyError
,而如果您使用 dict 的 get()
方法,您可以指定默认值。我指定了默认的空字符串,这样 split() 就不会抛出 AttributeError
。就是这样。
@Ben。谢谢它对我有用。你也能回答这个问题吗?我相信这只是这个问题的延伸***.com/questions/10410982/…。你能给我一个解决方案吗?
这很好用。不过,has_key()
已被弃用,取而代之的是 key in d
。但我知道你只是从 ha22109 的回答中得到的。一个问题:当你可以使用request.path_info
(更短)时,为什么还要使用request.META['PATH_INFO']
?【参考方案4】:
我知道这个问题现在已经很老了,但它仍然有效。我相信这是最正确的做法。它本质上与 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,)
【讨论】:
【参考方案5】:这是我使用重定向的通用解决方案,它只是检查是否有任何 GET 参数,如果不存在,则使用默认的 get 参数重定向。我还设置了一个 list_filter,因此它会选择它并显示默认值。
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_view 功能。这是过滤器:
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_view 现在只在不存在的情况下传递默认参数。这个想法是摆脱泛型过滤器的能力,通过不使用获取参数来查看所有内容。查看我为此目的分配了 status = 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)
【讨论】:
我有一个修复我的警告,一个自定义过滤器。我将把它作为替代解决方案。 谢谢,我发现重定向是最干净和最简单的解决方案。我也不明白“警告”。我总是得到想要的结果,无论是通过点击还是使用直接链接(我没有使用自定义过滤器)。【参考方案6】: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 )
if len( qstr ) < 2:
default_filter = True
except:
default_filter = True
if default_filter:
q = request.GET.copy()
q['registered__exact'] = '1'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super( InterestAdmin, self ).changelist_view( request, extra_context = extra_context )
【讨论】:
【参考方案7】:你可以简单地使用return queryset.filter()
或if self.value() is None
和SimpleListFilter的Override方法
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,
【讨论】:
【参考方案8】:受此处的一些答案(主要是 Greg 的)启发,创建了一个可重用的 Filter 子类。
优点:
可重用 - 可插入任何标准ModelAdmin
类
可扩展 - 轻松为QuerySet
过滤添加额外/自定义逻辑
易于使用 - 在其最基本的形式中,只需要实现一个自定义属性和一个自定义方法(除了 SimpleListFilter 子类化所需的那些)
直观的管理 - “全部”过滤器链接按预期工作;和其他人一样
无重定向 - 无需检查 GET
请求有效负载,与 HTTP_REFERER
无关(或任何其他与请求相关的内容,其基本形式)
没有(更改列表)视图操作 - 并且没有模板操作(上帝保佑)
代码:
(大部分import
s 仅用于类型提示和异常)
from typing import List, Tuple, Any
from django.contrib.admin.filters import SimpleListFilter
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.views.main import ChangeList
from django.db.models.query import QuerySet
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
class PreFilteredListFilter(SimpleListFilter):
# Either set this or override .get_default_value()
default_value = None
no_filter_value = 'all'
no_filter_name = _("All")
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = None
# Parameter for the filter that will be used in the URL query.
parameter_name = None
def get_default_value(self):
if self.default_value is not None:
return self.default_value
raise NotImplementedError(
'Either the .default_value attribute needs to be set or '
'the .get_default_value() method must be overridden to '
'return a URL query argument for parameter_name.'
)
def get_lookups(self) -> List[Tuple[Any, str]]:
"""
Returns a list of tuples. The first element in each
tuple is the coded value for the option that will
appear in the URL query. The second element is the
human-readable name for the option that will appear
in the right sidebar.
"""
raise NotImplementedError(
'The .get_lookups() method must be overridden to '
'return a list of tuples (value, verbose value).'
)
# Overriding parent class:
def lookups(self, request, model_admin) -> List[Tuple[Any, str]]:
return [(self.no_filter_value, self.no_filter_name)] + self.get_lookups()
# Overriding parent class:
def queryset(self, request, queryset: QuerySet) -> QuerySet:
"""
Returns the filtered queryset based on the value
provided in the query string and retrievable via
`self.value()`.
"""
if self.value() is None:
return self.get_default_queryset(queryset)
if self.value() == self.no_filter_value:
return queryset.all()
return self.get_filtered_queryset(queryset)
def get_default_queryset(self, queryset: QuerySet) -> QuerySet:
return queryset.filter(**self.parameter_name: self.get_default_value())
def get_filtered_queryset(self, queryset: QuerySet) -> QuerySet:
try:
return queryset.filter(**self.used_parameters)
except (ValueError, ValidationError) as e:
# Fields may raise a ValueError or ValidationError when converting
# the parameters to the correct type.
raise IncorrectLookupParameters(e)
# Overriding parent class:
def choices(self, changelist: ChangeList):
"""
Overridden to prevent the default "All".
"""
value = self.value() or force_str(self.get_default_value())
for lookup, title in self.lookup_choices:
yield
'selected': value == force_str(lookup),
'query_string': changelist.get_query_string(self.parameter_name: lookup),
'display': title,
完整使用示例:
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, )
希望这对某人有所帮助;反馈总是很感激。
【讨论】:
【参考方案9】:请注意,如果您不想预先选择过滤器值,而是希望始终在将数据显示在管理员中之前对其进行预先过滤,则应改写 ModelAdmin.queryset()
方法。
【讨论】:
这是一个非常干净和快速的解决方案,尽管它仍然可能会导致问题。在管理员中启用过滤选项后,用户可能会得到看似不正确的结果。如果被覆盖的查询集包含一个 .exclude() 子句,那么被该子句捕获的记录将永远不会被列出,但管理 UI 仍将提供显式显示它们的管理过滤选项。 还有其他更正确但票数较低的答案适用于这种情况,因为 OP 已明确要求他将放置一个过滤器,其中查询集将是错误的解决方案,正如 @ 所指出的那样上面的 TomasAndrle。 感谢@eskhool 指出这一点,我试图将我的答案否决为零,但似乎不允许对自己投反对票。【参考方案10】:使用 DjangoChoices、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 的出色解决方案!
【讨论】:
【参考方案11】:我知道这不是最好的解决方案,但我更改了管理模板中的 index.html,第 25 行和第 37 行,如下所示:
25:<th scope="row"><a href=" model.admin_url % ifequal model.name "yourmodelname" %?yourflag_flag__exact=1% endifequal %"> model.name </a></th>
37:<td><a href=" model.admin_url % ifequal model.name "yourmodelname" %?yourflag__exact=1% endifequal %" class="changelink">% trans 'Change' %</a></td>
【讨论】:
【参考方案12】:这是我能够生成的最干净的过滤器版本,该过滤器具有重新定义的“全部”和选中的默认值。
如果默认显示当前正在发生的旅行。
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()
【讨论】:
【参考方案13】:我必须进行修改才能使过滤正常工作。加载页面时,以前的解决方案对我有用。如果执行了“操作”,过滤器将返回“全部”,而不是我的默认设置。此解决方案使用默认过滤器加载管理员更改页面,但当页面上发生其他活动时,还会维护过滤器更改或当前过滤器。我没有测试所有情况,但实际上它可能会限制默认过滤器的设置仅在页面加载时发生。
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)
【讨论】:
【参考方案14】:有点跑题了,但我对类似问题的搜索把我带到了这里。我希望按日期进行默认查询(即,如果未提供输入,则仅显示带有timestamp
of '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_params
,它确保过滤器下拉列表将更新为与self.used_parameters
匹配的任何选项。出于这个原因,您必须确保 self.used_parameters
正是这些下拉选择之一将使用的内容(即,找出使用“今天”或“过去 7 天”时的 date_params
并构造self.used_parameters
匹配那些)。
这是为与 Django 1.4.10 一起工作而构建的
【讨论】:
【参考方案15】:这可能是一个旧线程,但我想我会添加我的解决方案,因为我在谷歌搜索中找不到更好的答案。
在 ModelAdmin 中为 changelist_view 回答了什么(不确定是 Deminic Rodger 还是 ha22109)
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
【讨论】:
我发现我需要在选择函数的 yield 调用中使用“force_text”(又名 force_unicode)函数,否则选择的过滤器选项不会显示为“已选择”。也就是“'selected': self.value() == force_text(lookup),"【参考方案16】:使用 ha22109 的回答,我为 ModelAdmin 类编写了一个 mixin:
from urllib.parse import urlencode
from django.contrib.admin.views.main import SEARCH_VAR
from django.http import HttpRequest, QueryDict
class DefaultFilterMixin:
default_filters: Sequence[tuple[str, Any]] | dict[str, Any] | None = None
def get_default_filters(
self,
request: HttpRequest,
) -> Sequence[tuple[str, Any]] | dict[str, Any] | None:
return self.default_filters
def changelist_view(
self,
request: HttpRequest,
extra_context: dict[str, str] | None = None,
):
if request.method == 'GET' and not request.GET:
if default_filters := self.get_default_filters(request):
request.GET = QueryDict(
f"urlencode(default_filters)&SEARCH_VAR=",
encoding=request.encoding,
)
request.META['QUERY_STRING'] = request.GET.urlencode()
return super().changelist_view(request, extra_context=extra_context)
简单示例:
class MyModelAdmin(DefaultFilterMixin, admin.ModelAdmin):
default_filters = (("status__exact", "pending"),)
...
或者更复杂的 rangefilter.DateTimeRangeFilter 动态过滤器:
class MyModelAdmin(DefaultFilterMixin, admin.ModelAdmin):
def get_default_filters(
self,
request: HttpRequest,
) -> Sequence[tuple[str, Any]] | dict[str, Any] | None:
now = timezone.now()
date_fmt = '%d.%m.%Y'
return (
('created_at__range__gte_0', now.strftime(date_fmt)),
('created_at__range__gte_1', '00:00:00'),
('created_at__range__lte_0', (now + timedelta(1)).strftime(date_fmt)),
('created_at__range__lte_1', '00:00:00'),
)
【讨论】:
【参考方案17】:使用默认 mixin 回复第一个答案(来自 Evgeni Shudzel)...这是一个导入和复杂性较少的解决方案
from urllib.parse import urlencode
from django.contrib.admin.views.main import SEARCH_VAR
from django.http import HttpRequest, QueryDict
class DefaultFilterMixin:
default_filters: None
def get_default_filters(self, request: HttpRequest):
return self.default_filters
def changelist_view(self, request: HttpRequest, extra_context=None):
if request.method == 'GET' and not request.GET:
if default_filters := self.get_default_filters(request):
request.GET = QueryDict(
f"urlencode(default_filters)&SEARCH_VAR=",
encoding=request.encoding,
)
request.META['QUERY_STRING'] = request.GET.urlencode()
return super().changelist_view(request, extra_context=extra_context)
class SampleUsageAdmin(DefaultFilterMixin, admin.ModelAdmin):
default_filters = (("fulfillments_complete__exact", "0"),)
【讨论】:
以上是关于Django admin 中的默认过滤器的主要内容,如果未能解决你的问题,请参考以下文章
Django admin.py 过滤器中的 HTML 输入文本框
Django学习---Templates过滤器及Django shell和Admin增强