zoukankan      html  css  js  c++  java
  • django admin-过滤器

    django框架的admin模块,通过list_filter提供给用户自定义分类查询的接口,并且我们可以在原有类的基础上扩展出符合自身应用场景的过滤器。

    定义模型

    以 Student 模型为准,管理类为 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创建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页面的右侧,通过 list_filter 可以直接激活 Student 中已经存在的模型。注:list_filter 应该是一个列表或元组。

    # 直接激活
    list_filter = ('first_name',)
    

    Filter 会自动列出所有不同的姓:

     
    1-直接激活.png

    当然,其指定的字段应该是BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey 或ManyToManyField中的一种。并且其属性可以为对应关联的外键,通过两个下划线指定关联表中对应属性:FK__key

    激活带选项的属性

    很多时候,我们的属性只有固定的几种类别,比如性别;一般我们会为该属性绑定选项,这样在展示时也更加直观:

    choices_gender = [
        (0, 'male'),
        (1, 'femal'),
    ]
    

    这时,我们在激活该属性的过滤器,显示的就是选项所对应的值,而不是数据库真正存储的值:

     
    2-激活带选项的属性.png

    自定义查询的过滤器(SimpleListFilter)

    继承自 django.contrib.admin.SimpleListFilter 的类,需要给它提供 titleparameter_name 属性来重写 lookupsqueryset 方法,title为页面上该过滤器的标题、parameter为加载页面时url中携带的参数名称:

    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 会列出 lookups 中定义的选项:

     
    3-自定义查询的过滤器.png

    日期的区间筛选(DateRangeFilter)

    默认的时间筛选只能选取某一段时间至今这样的区间,而daterange_filter插件提供了自定义时间区间的筛选。使用DateRangeFilter 前需要安装插件包 pip install django-daterange-filter,并在settings.pyINSTALLED_APPS 中添加 daterange_filter

    list_filter = (('birthday', DateRangeFilter), )
    
     
    4-时间区间的过滤.png

    自定义输入框查询(SingleTextInputFilter)

    django自带的过滤器是不含输入框的,但是我们可以自己重写一个带输入框的过滤器,并且自己指定样式:

    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.pyTEMPLATES'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 %}
    
     
    5-自定义输入框查询.png


    作者:Jerakrs
    链接:https://www.jianshu.com/p/09ff09d08f75
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    为什么java使用对象序列化到文件,打开之后是乱码,而且更换编码格式查看也不能正常显示呢
    String类能够导入IDEA,但是里面的构造方法无法使用,一直显示报错
    IDEA不能提示导入java.io.File类,但是自己手写import没问题,最后找到了问题所在
    扑克牌发牌,排序的功能实现
    TFS 生成定义
    Git-tfs工具
    日期和时间
    调用惯例
    优化查找和排序
    使用更好的库
  • 原文地址:https://www.cnblogs.com/feifeifeisir/p/12870225.html
Copyright © 2011-2022 走看看