V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
leisurelylicht
V2EX  ›  Python

django_filter 怎么用 choice 的值进行过滤

  •  
  •   leisurelylicht · 2019-01-24 19:06:32 +08:00 · 2564 次点击
    这是一个创建于 2137 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我有一个 model IPInfo

    class IPInfoModel(models.Model):
        TYPE_INTRANET = 1
        TYPE_INTERNET = 2
        IP_TYPES = (
            (TYPE_INTRANET, u'内网'),
            (TYPE_INTERNET, u'外网'),
        )
        ip = models.GenericIPAddressField("IP", unique=True)
        ip_type = models.SmallIntegerField(choices=IP_TYPES)
    

    然后我用 django_filter 做过滤

    from django_filters import rest_framework as django_filters 
    
    class IPInfoFilter(django_filters.FilterSet):
        ip_type = django_filters.ChoiceFilter(choices=IPInfoModel.IP_TYPES)
    
        class Meta:
            model = IPInfoModel
            fields = ["ip_type",]
    
    
    class IPInfoViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
        queryset = IPInfoModel.objects.all()
        serializer_class = IPInfoSerializer
        filter_class = IPInfoFilter
    

    过滤 ip_type 的时候,我想用 choice 的值“内网“、“外网”做参数值,而不是“ 1 ”和“ 2 ”。

    我该怎么做?

    10 条回复    2019-01-25 20:13:18 +08:00
    arischow
        1
    arischow  
       2019-01-24 22:19:09 +08:00 via iPhone
    IPInfoModel.TYPE_INTRANET
    chi1st
        2
    chi1st  
       2019-01-24 23:40:53 +08:00
    @arischow A 佬?
    leisurelylicht
        3
    leisurelylicht  
    OP
       2019-01-25 00:25:57 +08:00
    @arischow ? 这... 什么意思?
    yim7
        4
    yim7  
       2019-01-25 03:27:32 +08:00
    你可以写一个函数做映射,或者两个常量直接定义为字符串...
    XiaolinLeo
        5
    XiaolinLeo  
       2019-01-25 07:56:30 +08:00
    filter_class .get_ip_type_display 试试
    arischow
        6
    arischow  
       2019-01-25 09:41:29 +08:00 via iPhone
    @chi1st 是我
    freakxx
        7
    freakxx  
       2019-01-25 09:49:33 +08:00
    不过你数据库存的是 1,2 呀,
    不过无论想怎么搞,一般在前端层面的去做 widgets 就 ok 了。

    思路这么进去

    看这个库的 225 行
    ```
    class ChoiceFilter(Filter):
    field_class = ChoiceField # 这一行

    def __init__(self, *args, **kwargs):
    self.null_value = kwargs.get('null_value', settings.NULL_CHOICE_VALUE)
    super(ChoiceFilter, self).__init__(*args, **kwargs)

    def filter(self, qs, value):
    if value != self.null_value:
    return super(ChoiceFilter, self).filter(qs, value)

    qs = self.get_method(qs)(**{'%s__%s' % (self.field_name, self.lookup_expr): None})
    return qs.distinct() if self.distinct else qs
    ```


    然后追溯到 django 的 form widgets, 第 550 行,
    s

    ```
    def render_option(self, selected_choices, option_value, option_label):
    if option_value is None:
    option_value = ''
    option_value = force_text(option_value)
    if option_value in selected_choices:
    selected_html = mark_safe(' selected="selected"')
    if not self.allow_multiple_selected:
    # Only allow for a single selection.
    selected_choices.remove(option_value)
    else:
    selected_html = ''
    return format_html('<option value="{}"{}>{}</option>', option_value, selected_html, force_text(option_label))

    ```


    然后再把 allow none 那个----也做个处理就 OK 了。
    leisurelylicht
        8
    leisurelylicht  
    OP
       2019-01-25 11:21:44 +08:00
    @XiaolinLeo 这个是显示用的,不能用于查询
    @freakxx @yim7 多谢提供思路
    freakxx
        9
    freakxx  
       2019-01-25 11:51:26 +08:00
    @leisurelylicht

    你把 option_value 改为 lforce_text(option_label) 就可以了。

    另外一种做法是,自定义 filter,做个 dict,key,value 再做一遍反向查询。
    leisurelylicht
        10
    leisurelylicht  
    OP
       2019-01-25 20:13:18 +08:00
    @freakxx option_value 和 lforce_text 是 django_filter 里的参数吗?我在文档里没搜到?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2681 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:51 · PVG 19:51 · LAX 03:51 · JFK 06:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.