[英]How to add custom filtering fields to an Django Rest Framework APIListView
I'm using django rest framework and I have a ListAPIView that I would like to implement a complex filtering functionality that I'm using Q filters.我正在使用 django rest 框架,我有一个 ListAPIView,我想实现一个复杂的过滤功能,我正在使用 Q 过滤器。 My question is how do I generate custom fields for this filtering?我的问题是如何为此过滤生成自定义字段?
url: path('', EventListView.as_view(), name='event_list_view'),
url: path('', EventListView.as_view(), name='event_list_view'),
serializer:序列化器:
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
exclude = ('user', )
View:看法:
class EventListView(ListAPIView):
authentication_classes = ()
permission_classes = ()
serializer_class = EventSerializer
filter function:过滤器 function:
def filter_events(
user: User, sort_by: int = DISTANCE, privacy_levels: [int] = [EVERYONE], categories: [Category] = None,
start_date: datetime.datetime = DEFAULT_START_DATE, end_date: datetime.datetime = DEFAULT_END_DATE,
distance: int = DEFAULT_DISTANCE, current_location: Point = None, unit: int = None,
clubs: [UniversityClub] = None, universities: [University] = None,
greeks: [GreekOrganization] = None, groups: [UserGroup] = None, users_p: [User] = None
):
....
if EVERYONE in privacy_levels:
everyone_q = Q(privacy_level=EVERYONE, university__in=user_universities, start_time__range=[start_date, end_date])
else:
everyone_q = Q()
if STUDENTS in privacy_levels:
student_q = Q(privacy_level=STUDENTS, start_time__range=[start_date, end_date])
else:
student_q = Q()
...
I would recommend you to have a look atdjango-filter
and DjangoFilterBackend
for DRF :我建议你看看 DRF 的django-filter
和DjangoFilterBackend
:
The django-filter library includes a DjangoFilterBackend class which supports highly customizable field filtering for REST framework. django-filter 库包括一个 DjangoFilterBackend class,它支持 REST 框架的高度可定制的字段过滤。
django-filter
is very powerful and allows you to define reusable and combinable filters. django-filter
非常强大,允许您定义可重用和可组合的过滤器。 Example:例子:
class EventFilter(django_filters.FilterSet):
privacy_level = django_filters.ChoiceFilter(choices=PRIVACY_LEVELS)
class Meta:
model = Event
You can also provide your own filtering method if you want to implement custom filtering logic:如果要实现自定义过滤逻辑,也可以提供自己的过滤方法:
class EventFilter(django_filters.FilterSet):
privacy_level = django_filters.ChoiceFilter(choices=PRIVACY_LEVELS, method='filter_privacy_level')
def filter_privacy_level(self, queryset, name, value):
# Filter upon given privacy level
queryset = queryset.filter(privacy_level=value)
# Apply your custom logic given the privacy_level
if value == UNIVERSITY:
queryset = queryset.filter(another_field='foo')
return queryset
class Meta:
model = Event
The beauty behind this is that each Filter
will return a queryset
;这背后的美妙之处在于每个Filter
都会返回一个queryset
; which allows django-filter
to chain them and thus to allow any combinations of filters.这允许django-filter
链接它们,从而允许过滤器的任何组合。
However, in your specific case, you'll need the current user in your filter method.但是,在您的特定情况下,您需要过滤方法中的当前用户。 We can also do that by customizing the DjangoFilterBackend
:我们也可以通过自定义DjangoFilterBackend
来做到这一点:
class UserFilterBackend(filters.DjangoFilterBackend):
def get_filterset_kwargs(self, request, queryset, view):
# Get the default constructor kwargs
kwargs = super().get_filterset_kwargs(request, queryset, view)
# Add the current user in it
kwargs['user'] = request.user
return kwargs
class EventFilter(django_filters.FilterSet):
privacy_level = django_filters.ChoiceFilter(choices=PRIVACY_LEVELS, method='filter_privacy_level')
# Overload the default constructor to retrieve the user in kwargs
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
# Keep the user in the filter instance
self.user = user
def filter_privacy_level(self, queryset, name, value):
# Filter upon given privacy level
queryset = queryset.filter(privacy_level=value)
# Apply your custom logic given the privacy_level
if value == UNIVERSITY:
# Great, we can retrieve the user universities!
queryset = queryset.filter(university__in=self.user.universities)
return queryset
class Meta:
model = Event
Of course, you should now use your UserFilterBackend
instead of filters.DjangoFilterBackend
in the filter_backends
of your viewset.当然,您现在应该在视图集的filter_backends
中使用您的UserFilterBackend
而不是filters.DjangoFilterBackend
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.