Xiang Wang @ 2017-03-01 10:04:45
DjangoFilterBackend
def get_filterset(self, request, queryset, view):
filterset_class = self.get_filterset_class(view, queryset)
if filterset_class is None:
return None
kwargs = self.get_filterset_kwargs(request, queryset, view)
return filterset_class(**kwargs)
def get_filterset_class(self, view, queryset=None):
"""
return the `FilterSet` class used to filter the queryset
"""
filterset_class = getattr(view, 'filterset_class', None)
filterset_fields = getattr(view, 'filterset_fields', None)
if filterset_class:
使用这个filterset_class
if filterset_fields and queryset is not None:
MetaBase = getattr(self.filterset_base, "Meta", object)
class AutoFilterSet(self.filterset_base):
class Meta(MetaBase):
mode = queryset.model
fileds = filterset_fields
return AutoFilterSet
return None
def filter_queryset(self, request, queryset, view):
filterset = self.get_filterset(request, queryset, view)
if filterset is None
return queryset
if not filterset.is_valid() and self.raise_exception:
raise utils.translate_validation(filterset.errors)
return filterset.qs
django-filter基础
pip install django-filter
import django_filters
class MyFilter(django_filters.rest_framework.FilterSet):
type = django_filters.NumberFilter(name="type", lookup_expr="gte")
name = django_filters.CharFilter(name='name')
has_reply = django_filters.BooleanFilter(method='filter_reply')
order_by = django_filters.OrderingFilter(
fields=(
("level", "level"), # 前面的代表在queryset用的,后面的代表在params里用的
("customer__focus", "customer__focus"),
)
)
def filter_reply(self, queryset, name, value):
if value is True:
return queryset.exclude(reply="")
else:
return queryset.filter(reply="")
class Meta:
model = models.Model
fields = ("type", "name")
class MyView(ListAPIView):
filter_class = MyFilter
queryset = MyFilter({'type': 'type1'}, models.Model.objects.all()).qs
core arguments
field_name查找哪个字段lookup_expr查找的时候的后缀添加属性help_text备注信息required默认False,是否需要。如果为True的话,就会返回空的querysetmethod使用哪个方法来过滤inbox = django_filters.BooleanFilter(method="filter_inbox") # 如果是BooleanFilter, 那么 MyFilter({'inbox': 'false'}, queryset).qs 会导致无法过滤。必须validated_data才能进行过滤 # TODO 如果是前端传递的bool值,会怎么样。rest-framework会进行validate吗 def filter_inbox(self, queryset, name, value): return queryset
exclude是否要用exclude
Filter
所有的filter
def filter_queryset(self, queryset):
for name, value in self.form.cleaned_data.items():
queryset = self.filters[name].filter(queryset, value)
assert isintance(queryset, models.QuerySet)
return queryset
MultiChoiceFilter 官网
使用了多重过滤,以后输入 url?_type=类型1&_type=类型2 就能过滤几个url
_type = django_filters.MultipleChoiceFilter(
choices=models.TestFilter.TYPE_CHOICE
)
/django_filters/filters.py line 231
class MultipleChoiceFilter(Filter):
def filter(self, qs, value):
...
for v in set(value):
if v == self.null_value:
v = None
predicate = self.get_filter_predicate(v)
if self.conjoined:
qs = self.get_method(qs)(**predicate)
else:
q |= Q(**predicate)
if not self.conjoined:
qs = self.get_method(qs)(q)
return qs.distinct() if self.distinct else qs
...
def get_filter_predicate(self, v):
name = self.field_name
if name and self.lookup_expr != 'exact':
name = LOOKUP_SEP.join([name, self.lookup_expr])
try:
return {name: getattr(v, self.field.to_field_name)}
except (AttributeError, TypeError):
return {name: v}
ModelChoiceFilter 参考
author = django_filters.ModelChoiceFilter(queryset=Author.objects.all())
def myqueryset(request):
return request.user.friends.all()
user = django_filters.ModelChoiceFilter(queryset=myqueryset) # 当然也可以自定义一个queryset函数,必须接受一个request参数
ChoiceFilter 参考
STATUS_CHOICES = ( (0, 'regular'), (1, 'manager'), (2, 'admin'), ) status = ChoiceFilter(choices=STATUS_CHOICES)
BooleanFilter 参考
def filter_bool(self, queryset, name, value): # 前端必须传递 True 和 False 的首字母大写字符串。如果传递错了,就不进行过滤 assert value in [True, False]
IsoDateTimeFilter 参考
示例
{'time__gt': '2017-12-11T11:19:28+00:00'} # 这种标准的格式肯定没有问题的 {'time__gt': '2017-12-11 08:19:27'} # 这种不标准的格式就会默认当作当前时区,所以就算是传递的 08 时,这个00UTC时的数据也会显示出来
RangeFilter
用法
class F(FilterSet):
"""Filter for Books by Price"""
price = RangeFilter()
class Meta:
model = Book
fields = ['price']
qs = Book.objects.all().order_by('title')
# Range: Books between 5€ and 15€
f = F({'price_min': '5', 'price_max': '15'}, queryset=qs)
# Min-Only: Books costing more the 11€
f = F({'price_min': '11'}, queryset=qs)
# Max-Only: Books costing less than 19€
f = F({'price_max': '19'}, queryset=qs)
原理
DateFromToRangeFilter
用法
class F(FilterSet):
date = DateFromToRangeFilter()
class Meta:
model = Comment
fields = ['date']
f = F({'date_after': '2016-01-01', 'date_before': '2016-02-01'})
```