Python中如何使用django_filter根据choice字段的值进行过滤?
我有一个 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 ”。
我该怎么做?
Python中如何使用django_filter根据choice字段的值进行过滤?
IPInfoModel.TYPE_INTRANET
# 假设你的models.py中有这样的模型定义
from django.db import models
class MyModel(models.Model):
STATUS_CHOICES = [
('active', '活跃'),
('inactive', '不活跃'),
('pending', '待处理'),
]
status = models.CharField(max_length=10, choices=STATUS_CHOICES)
name = models.CharField(max_length=100)
# 在filters.py中创建过滤器
import django_filters
from .models import MyModel
class MyModelFilter(django_filters.FilterSet):
# 方法1:使用ChoiceFilter(推荐)
status = django_filters.ChoiceFilter(
choices=MyModel.STATUS_CHOICES,
label='状态'
)
# 方法2:如果需要自定义查询行为
status_exact = django_filters.ChoiceFilter(
field_name='status',
choices=MyModel.STATUS_CHOICES,
method='filter_status',
label='精确匹配状态'
)
def filter_status(self, queryset, name, value):
# 这里可以添加自定义过滤逻辑
return queryset.filter(status=value)
class Meta:
model = MyModel
fields = ['status', 'name']
# 在views.py中使用
from django_filters.views import FilterView
from .models import MyModel
from .filters import MyModelFilter
class MyModelListView(FilterView):
model = MyModel
filterset_class = MyModelFilter
template_name = 'mymodel_list.html'
paginate_by = 20
# 或者在函数视图中使用
from django.shortcuts import render
from .filters import MyModelFilter
def mymodel_list(request):
queryset = MyModel.objects.all()
myfilter = MyModelFilter(request.GET, queryset=queryset)
return render(request, 'mymodel_list.html', {'filter': myfilter})
# 在模板中(mymodel_list.html)使用
"""
<form method="get">
{{ filter.form.as_p }}
<button type="submit">筛选</button>
</form>
<table>
{% for obj in filter.qs %}
<tr>
<td>{{ obj.name }}</td>
<td>{{ obj.get_status_display }}</td>
</tr>
{% endfor %}
</table>
"""
核心就是使用django_filters.ChoiceFilter并传入模型的choices选项。这样会自动生成下拉选择框,用户可以选择预定义的值进行过滤。记得在FilterSet的Meta类中指定模型和字段。
简单说就是:用ChoiceFilter绑定模型的choices字段。
A 佬?
? 这… 什么意思?
你可以写一个函数做映射,或者两个常量直接定义为字符串…
是我
不过你数据库存的是 1,2 呀,
不过无论想怎么搞,一般在前端层面的去做 widgets 就 ok 了。
思路这么进去
看这个库的 225 行<br>class ChoiceFilter(Filter):<br> field_class = ChoiceField # 这一行<br><br> def __init__(self, *args, **kwargs):<br> self.null_value = kwargs.get('null_value', settings.NULL_CHOICE_VALUE)<br> super(ChoiceFilter, self).__init__(*args, **kwargs)<br><br> def filter(self, qs, value):<br> if value != self.null_value:<br> return super(ChoiceFilter, self).filter(qs, value)<br><br> qs = self.get_method(qs)(**{'%s__%s' % (self.field_name, self.lookup_expr): None})<br> return qs.distinct() if self.distinct else qs<br>
然后追溯到 django 的 form widgets, 第 550 行,
s<br> def render_option(self, selected_choices, option_value, option_label):<br> if option_value is None:<br> option_value = ''<br> option_value = force_text(option_value)<br> if option_value in selected_choices:<br> selected_html = mark_safe(' selected="selected"')<br> if not self.allow_multiple_selected:<br> # Only allow for a single selection.<br> selected_choices.remove(option_value)<br> else:<br> selected_html = ''<br> return format_html('<option value="{}"{}>{}</option>', option_value, selected_html, force_text(option_label))<br><br>
然后再把 allow none 那个----也做个处理就 OK 了。
这个是显示用的,不能用于查询
多谢提供思路
你把 option_value 改为 lforce_text(option_label) 就可以了。
另外一种做法是,自定义 filter,做个 dict,key,value 再做一遍反向查询。
option_value 和 lforce_text 是 django_filter 里的参数吗?我在文档里没搜到?

