Django admin.py 过滤器中的 HTML 输入文本框
Posted
技术标签:
【中文标题】Django admin.py 过滤器中的 HTML 输入文本框【英文标题】:HTML input textbox in Django admin.py filter 【发布时间】:2011-09-27 15:18:27 【问题描述】:我想在 Django (admin.py) 中使用 html 输入文本框中的文本过滤数据。我需要按他们所在的城市过滤公司,并且所有城市的列表太长。我想用一个文本输入替换过滤器中所有城市的列表。我发现了类似的东西 这里http://djangosnippets.org/snippets/2429/但是有两个问题:
-
作者没有发布models.py,因此很难根据我的需要更改代码(+ 没有cmets)
使用了 UserFieldFilterSpec(RelatedFilterSpec) 类:但我需要使用 AllValuesFilterSpec 而不是 RelatedFilterSpec(更多信息在文件 django/contrib/admin/filterspecs.py 中),因为城镇列表与 comapny 属于同一类(应该按城镇类别,它们应该通过外键引用公司(多对多关系),但由于某些原因,必须这样做)
models.py 的重要部分看起来像这样
class Company(models.Model):
title = models.CharField(max_length=150,blank=False)
city = models.CharField(max_length=50,blank=True)
还有一些来自 admin.py 的东西
class CatalogAdmin(admin.ModelAdmin):
form = CatalogForm
list_display = ('title','city')
list_filter = ['city',]
再说一次,我需要: 1. 在 Django 过滤器中显示一个文本输入,而不是列出 od 城市 2. 在该文本输入中输入城市名称后,按城市过滤数据(过滤请求可以通过一些提交按钮或通过javascript发送)
感谢您的所有帖子。
【问题讨论】:
【参考方案1】:如果有人仍然需要这个。它在模板中有点hackish,但在没有一段js的情况下实现。
filters.py
:
from django.contrib.admin import ListFilter
from django.core.exceptions import ImproperlyConfigured
class SingleTextInputFilter(ListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, request, params, model, model_admin):
super(SingleTextInputFilter, self).__init__(
request, params, model, model_admin)
if self.parameter_name is None:
raise ImproperlyConfigured(
"The list filter '%s' does not specify "
"a 'parameter_name'." % self.__class__.__name__)
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice =
'selected': self.value() is None,
'query_string': cl.get_query_string(, [self.parameter_name]),
'display': _('All'),
return (
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
, )
templates/admin/textinput_filter.html
:
% load i18n %
<h3>% blocktrans with filter_title=title % By filter_title % endblocktrans %</h3>
#i for item, to be short in names#
% with choices.0 as i %
<ul>
<li>
<form method="get">
<input type="search" name=" i.parameter_name " value=" i.current_value|default_if_none:"" "/>
#create hidden inputs to preserve values from other filters and search field#
% for k, v in i.get_query.items %
% if not k == i.parameter_name %
<input type="hidden" name=" k " value=" v ">
% endif %
% endfor %
<input type="submit" value="% trans 'apply' %">
</form>
</li>
#show "All" link to reset current filter#
<li% if i.all_choice.selected % class="selected"% endif %>
<a href=" i.all_choice.query_string|iriencode ">
i.all_choice.display
</a>
</li>
</ul>
% endwith %
然后根据你在admin.py
中的模型:
class CatalogCityFilter(SingleTextInputFilter):
title = 'City'
parameter_name = 'city'
def queryset(self, request, queryset):
if self.value():
return queryset.filter(city__iexact=self.value())
class CatalogAdmin(admin.ModelAdmin):
form = CatalogForm
list_display = ('title','city')
list_filter = [CatalogCityFilter,]
准备使用的过滤器看起来像这样。
【讨论】:
非常感谢您提供此代码 sn-p!你刚刚为我节省了几个小时的工作时间。但是,您的示例中有一个小错误:CatalogCityFilter.queryset
调用应返回查询集。
@devsnd 此代码在您的情况下是否引发异常?正如我从 django 资料中看到的那样:对于 self.filter_specs 中的 filter_spec:new_qs = filter_spec.queryset(request, qs) if new_qs is not None: qs = new_qs github.com/django/django/blob/master/django/contrib/admin/views/… if filter 返回 None 没有任何反应。
无异常,但在返回查询集之前它不起作用,因为 filter
返回应用了过滤器的查询集的新副本。
@devsnd 哦,是的,很抱歉,现在我明白了。只是在现有项目中查看我的代码,而不是我的答案。一定是一些蟒蛇精灵带走了我的return
:) 修复它。
我已经寻找这个解决方案 2 个月了。非常感谢您的好心先生!【参考方案2】:
我正在运行 Django 1.10、1.11 和 r_black 的 solution 不完全适合,因为 Django 抱怨过滤器字段必须继承自 'FieldListFilter'。
因此,从 FieldListFilter 继承的过滤器的简单更改处理了 Django 的抱怨,而不必同时为每个字段指定一个新类。
class SingleTextInputFilter(admin.FieldListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, field, request, params, model, model_admin, field_path):
super().__init__(field, request, params, model, model_admin, field_path)
if self.parameter_name is None:
self.parameter_name = self.field.name
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def queryset(self, request, queryset):
if self.value():
return queryset.filter(imei__icontains=self.value())
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice =
'selected': self.value() is None,
'query_string': cl.get_query_string(, [self.parameter_name]),
'display': _('All'),
return (
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
, )
templates/admin/textinput_filter.html(不变):
% load i18n %
<h3>% blocktrans with filter_title=title % By filter_title % endblocktrans %</h3>
#i for item, to be short in names#
% with choices.0 as i %
<ul>
<li>
<form method="get">
<input type="search" name=" i.parameter_name " value=" i.current_value|default_if_none:"" "/>
#create hidden inputs to preserve values from other filters and search field#
% for k, v in i.get_query.items %
% if not k == i.parameter_name %
<input type="hidden" name=" k " value=" v ">
% endif %
% endfor %
<input type="submit" value="% trans 'apply' %">
</form>
</li>
#show "All" link to reset current filter#
<li% if i.all_choice.selected % class="selected"% endif %>
<a href=" i.all_choice.query_string|iriencode ">
i.all_choice.display
</a>
</li>
</ul>
% endwith %
用法:
class MyAdmin(admin.ModelAdmin):
list_display = [your fields]
list_filter = [('field 1', SingleTextInputFilter), ('field 2', SingleTextInputFilter), further fields]
【讨论】:
谢谢,您只需要删除查看特定 imei (telco?) 字段的自定义查询集函数。 嗯,不:该函数是执行过滤的函数。但是你确实需要用你自己的字段名重命名“imei”......实际上,我忘了在这个例子中修复那个;) 您可以通过编程方式填写字段名称,例如:return queryset.filter(**self.field.name: self.value())
【参考方案3】:
虽然这实际上不是您的问题,但这听起来是Django-Selectables 的完美解决方案,您只需几行即可添加一个 AJAX 驱动的 CharField 表单,该表单将从城市列表中选择其条目。查看上面链接中列出的示例。
【讨论】:
这真的不是我想要的。我的问题是显示有效的文本输入过滤器。自动完成功能很好,我想稍后添加。无论如何,谢谢您的回复。 好的,这是我自己想出来的。我在 filterspecs.py 中创建了自己的过滤器(我知道这样做很讨厌)。如果您以这种方式尝试,请小心注册您的过滤器。您的过滤器应该在系统过滤器之前注册。比在 models.py 中将您的过滤器分配给它所属的属性。在过滤器中,我使用了一些更改发布的 url 参数的东西。按一个城市过滤由 city=Prague 完成,但如果您想按过滤器列表过滤,请使用 city__in=Prague,Wien,Dublin。有很多更好的方法可以做到这一点(查询、AJAX、..),但我只是在学习。【参考方案4】:以下是查询集函数中字段名称的修复..
class SingleTextInputFilter(admin.FieldListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, field, request, params, model, model_admin, field_path):
super().__init__(field, request, params, model, model_admin, field_path)
if self.parameter_name is None:
self.parameter_name = self.field.name
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def queryset(self, request, queryset):
variable_column = self.parameter_name
search_type = 'icontains'
filter = variable_column + '__' + search_type
if self.value():
return queryset.filter(**filter: self.value())
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice =
'selected': self.value() is None,
'query_string': cl.get_query_string(, [self.parameter_name]),
'display': ('All'),
return (
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
, )
【讨论】:
以上是关于Django admin.py 过滤器中的 HTML 输入文本框的主要内容,如果未能解决你的问题,请参考以下文章
Django 命令行工具django-admin.py与manage.py
django-admin 和django-admin.py的区别
国际化时django.po中的msgstr =“”为中文时,django-admin.py compilemessages 出错:无效的多字节序列