您可以创建自己的基本过滤器,您可以从中继承和定义模型字段过滤器。
from django_filters import (
BaseInFilter,
BaseRangeFilter,
BooleanFilter,
FilterSet,
NumberFilter,
)
### first, create filterset class attributes
def create_custom_method_filters(filter_name, base_filter_class, lookups, func):
custom_method_name = f'filter_{filter_name}'
def custom_method(self, queryset, name, value):
return func(queryset, name, value)
boolean_lookups = ('isnull', 'isempty')
in_lookups = ('in',)
range_lookups = ('range',)
d = dict(
**{
f'{filter_name}__{lookup}' if lookup != 'exact' else filter_name: base_filter_class(method=custom_method_name)
for lookup in lookups
if lookup not in boolean_lookups + in_lookups + range_lookups
},
**{
f'{filter_name}__{lookup}': BooleanFilter(method=custom_method_name)
for lookup in lookups
if lookup in boolean_lookups
},
**{
f'{filter_name}__{lookup}': type('InFilter', (BaseInFilter, base_filter_class), {})(method=custom_method_name)
for lookup in lookups
if lookup in in_lookups
},
**{
f'{filter_name}__{lookup}': type('RangeFilter', (BaseRangeFilter, base_filter_class), {})(method=custom_method_name)
for lookup in lookups
if lookup in range_lookups
},
**{
custom_method_name: custom_method,
},
)
return d
### second, create your base filter for the specific filter
UserFilterBase = type(
'UserFilterBase',
(FilterSet,),
create_custom_method_filters(
'artworks_count',
NumberFilter,
['exact', 'in', 'gt', 'gt', 'lt', 'lte', 'range'],
lambda queryset, name, value: queryset.annotate(artworks_count=Count('artworks')).filter(**{name: value}),
),
)
### Then, inherit from that base class and use the filter meta as usual.
class UserFilter(UserFilterBase):
class Meta:
model = User
fields = {'age': ['exact', 'gte', 'lte', 'lt', 'gt', 'in']}
在 Python 3.9+ 中,您可以将丑陋的 dict(**{…}, **{…}) 构造替换为更好的 {…} | {…} 构造