Я бы рекомендовал вам взглянуть на django-filter
и DjangoFilterBackend
для DRF :
Библиотека django-filter включает в себя:Класс DjangoFilterBackend, который поддерживает настраиваемую фильтрацию полей для среды REST.
django-filter
очень мощный и позволяет вам определять повторно используемые и комбинируемые фильтры. Пример:
class EventFilter(django_filters.FilterSet):
privacy_level = django_filters.ChoiceFilter(choices=PRIVACY_LEVELS)
class Meta:
model = Event
Вы также можете предоставить свой собственный метод фильтрации , если вы хотите реализовать собственную логику фильтрации:
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
Вся прелесть в том, что каждыйFilter
вернет queryset
;что позволяет django-filter
объединять их в цепочку и, следовательно, разрешать любые комбинации фильтров.
Однако в вашем конкретном случае вам понадобится текущий пользователь в вашем методе фильтрации. Мы также можем сделать это, настроив 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
Конечно, теперь вы должны использовать UserFilterBackend
вместо filters.DjangoFilterBackend
в filter_backends
вашегоViewset.