django框架的admin模塊,通過list_filter提供給用戶自定義分類查詢的接口洪鸭,并且我們可以在原有類的基礎(chǔ)上擴(kuò)展出符合自身應(yīng)用場(chǎng)景的過濾器烤黍。
定義模型
以 Student 模型為準(zhǔn),管理類為 StudentAdmin先舷。
class Student(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(
max_length=20, verbose_name=u'姓')
last_name = models.CharField(
max_length=20, verbose_naem=u'名')
gender = models.IntegerField(
choices=choices_gender, verbose_name=u'性別')
age = models.IntegerField(
blank=True, verbose_name=u'年齡')
birthday = models.DateTimeField(
blank=True, verbose_name=u'生日')
@admin.register(Student)
class StudentAdmin(admin.ModelAdmin):
list_display = ('id', 'first_name', 'last_name', 'gender', 'age', 'birthday')
list_per_page = 20
mysql創(chuàng)建student表:
CREATE TABLE student(
id int(10) NOT NULL AUTO_INCREMENT,
first_name varchar(20) NOT NULL,
last_name varchar(20) NOT NULL,
gender int(10) NOT NULL,
age int(10) NOT NULL,
birthday datetime,
PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
直接激活過濾器
過濾器位于Admin頁面的右側(cè)哩盲,通過 list_filter 可以直接激活 Student 中已經(jīng)存在的模型仆抵。注:list_filter 應(yīng)該是一個(gè)列表或元組。
# 直接激活
list_filter = ('first_name',)
Filter 會(huì)自動(dòng)列出所有不同的姓:
當(dāng)然种冬,其指定的字段應(yīng)該是BooleanField镣丑、CharField、DateField娱两、DateTimeField莺匠、IntegerField、ForeignKey 或ManyToManyField中的一種十兢。并且其屬性可以為對(duì)應(yīng)關(guān)聯(lián)的外鍵趣竣,通過兩個(gè)下劃線指定關(guān)聯(lián)表中對(duì)應(yīng)屬性:FK__key
激活帶選項(xiàng)的屬性
很多時(shí)候,我們的屬性只有固定的幾種類別旱物,比如性別遥缕;一般我們會(huì)為該屬性綁定選項(xiàng),這樣在展示時(shí)也更加直觀:
choices_gender = [
(0, 'male'),
(1, 'femal'),
]
這時(shí)宵呛,我們?cè)诩せ钤搶傩缘倪^濾器单匣,顯示的就是選項(xiàng)所對(duì)應(yīng)的值,而不是數(shù)據(jù)庫真正存儲(chǔ)的值:
自定義查詢的過濾器(SimpleListFilter)
繼承自 django.contrib.admin.SimpleListFilter
的類宝穗,需要給它提供 title
和 parameter_name
屬性來重寫 lookups
和 queryset
方法户秤,title
為頁面上該過濾器的標(biāo)題、parameter
為加載頁面時(shí)url中攜帶的參數(shù)名稱:
from django.utils.translation import ugettext_lazy as _
class AgeListFilter(admin.SimpleListFilter):
title = _(u'年齡段')
parameter_name = 'ages'
def lookups(self, request, model_admin):
return (
('0', _(u'未成年')),
('1', _(u'成年人')),
('2', _(u'老年人')),
)
def queryset(self, request, queryset):
if self.value() == '0':
return queryset.filter(age__lt='18')
if self.value() == '1':
return queryset.filter(age__gte='18', age__lte='50')
if self.value() == '2':
return queryset.filter(age__gt='50')
# 激活自定義過濾器
list_filter = (AgeListFilter,)
Filter 會(huì)列出 lookups
中定義的選項(xiàng):
日期的區(qū)間篩選(DateRangeFilter)
默認(rèn)的時(shí)間篩選只能選取某一段時(shí)間至今這樣的區(qū)間逮矛,而daterange_filter插件提供了自定義時(shí)間區(qū)間的篩選鸡号。使用DateRangeFilter
前需要安裝插件包 pip install django-daterange-filter
,并在settings.py
的 INSTALLED_APPS
中添加 daterange_filter
须鼎。
list_filter = (('birthday', DateRangeFilter), )
自定義輸入框查詢(SingleTextInputFilter)
django自帶的過濾器是不含輸入框的鲸伴,但是我們可以自己重寫一個(gè)帶輸入框的過濾器府蔗,并且自己指定樣式:
from django.contrib.admin import ListFilter
class SingleTextInputFilter(ListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "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
}, )
class LastNameListFilter(SingleTextInputFilter):
title = 'Last Name'
parameter_name = 'last_name'
def queryset(self, request, queryset):
if self.value():
return queryset.filter(last_name=self.value())
將 textinput_filter.html放在templates文件夾下,并在settings.py
中TEMPLATES
的'DIRS'
汞窗,加上templates路徑姓赤。
{% 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 %}
參考文獻(xiàn)
- django 文檔
- django源碼:django/contrib/admin/filters.py
- django-daterange-filter
- stackoverflow