我正在使用django-filters
来过滤基于类的视图集上的数据。我在基于类的视图上使用filter_class
,它对视图集进行了初始过滤。我有一个单独的过滤器,可以按需过滤输出。
filters.py
class BookingFilterBackend(DRYPermissionFiltersBase):
def filter_list_queryset(self, request, queryset, view):
if request.user.is_role_admin:
return queryset
if request.user.is_role_client:
return queryset.filter(Q(client=request.user.client))
if request.user.is_role_camop:
return queryset.filter(Q(camera_operator=request.user))
return queryset.filter(Q(created_by=request.user))
class FilterOne(filters.FilterSet):
title = filters.CharFilter(method=filter_booking_title)
class Meta:
model = models.Booking
fields = [
'title',
'state',
'client',
]
class FilterTwo(filters.FilterSet):
client = filters.ModelMultipleChoiceFilter(queryset=users_models.Client.objects.all())
state = filters.MultipleChoiceFilter(choices=constants.BookingState)
camera_operator = filters.ModelMultipleChoiceFilter(queryset=users_models.UserManager.camop_users())
date_start = filters.DateFilter(name='date', lookup_expr='startswith')
date_end = filters.DateFilter(name='date', lookup_expr='endswith')
class Meta:
model = models.Booking
fields = [
'state',
'client',
'camera_operator',
'date_start',
'date_end',
]
api.py
class MyViewSet(
MultipleSerializerMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet
):
lookup_field = 'uuid'
queryset = models.Booking.objects.all()
filter_backends = [filters.BookingFilterBackend, DjangoFilterBackend, ]
filter_class = filters.FilterOne
pagination_class = BookingViewSetPagination
serializer_class = serializers.BookingDetailSerializer
serializer_classes = {
...
}
@list_route(methods=['POST'], url_path='export-bookings')
def export_bookings(self, request, *args, **kwargs):
queryset = self.get_queryset()
// just some debugging code
query_dict = request.data
print(query_dict.get('state', []))
print(query_dict.get('clients', []))
print(query_dict.get('camera_operators', []))
print(query_dict.get('from_date', ''))
print(query_dict.get('to_date', ''))
// Apply the filter set - FilterTwo - on my model objects -> Booking. Something like this:
// filtered_queryset = filters.FilterTwo(queryset, query_dict) - ??
return response.NoContent()
但是,我无法弄清楚如何用FilterTwo
(在POST调用的正文中收到)和原始的the query dictionary
来编写调用queryset
的语句。 >
第二,我的模态中有一个date
字段,我想在此字段上执行great_than和lesser_than。我不知道我的过滤器逻辑是否正确编写。
答案 0 :(得分:1)
您可以调用过滤器类filter_queryset方法
queryset = self.get_queryset()
queryset = self.filter_queryset(queryset)
答案 1 :(得分:0)
最后,在深入研究django FilterBackends和django_filters
的FilterSets之后,我了解了两者的概念和用法。虽然,我已经解决了这个问题,但肯定可以进一步改进它。 (我将其作为单独的问题发布在SO上。)
这是解决方案:
不必定义新的自定义FilterSet
,而是必须创建一个新的FilterBackend
并覆盖filter_queryset
方法。
filters.py
from django.db.models import Q
from django_filters import rest_framework as filters
from dry_rest_permissions.generics import DRYPermissionFiltersBase
from rest_framework import filters as generic_filters
# Project Local
from . import models, constants
from shootsta.users import models as users_models
class BookingFilterBackend(DRYPermissionFiltersBase):
def filter_list_queryset(self, request, queryset, view):
if request.user.is_role_admin:
return queryset
if request.user.is_role_client:
return queryset.filter(Q(client=request.user.client))
if request.user.is_role_camop:
return queryset.filter(Q(camera_operator=request.user))
return queryset.filter(Q(created_by=request.user))
# This is my new filter backend (I know the filtration logic looks very basic, I've come from a java background so spare me the rant.)
class MyNewFilterBackend(generic_filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
predicate = request.data
if all(k in predicate for k in ('from_date', 'to_date')):
queryset = queryset.filter(date__range=(predicate['from_date'], predicate['to_date']))
if 'from_date' in predicate and 'to_date' not in predicate:
queryset = queryset.filter(date__gte=predicate['from_date'])
if 'to_date' in predicate and 'from_date' not in predicate:
queryset = queryset.filter(date__lte=predicate['to_date'])
if 'state' in predicate:
queryset = queryset.filter(state__in=predicate['state'])
if 'clients' in predicate:
queryset = queryset.filter(client__in=predicate['clients'])
if 'camera_operators' in predicate:
queryset = queryset.filter(camera_operator__uuid__in=predicate['camera_operators'])
if 'recipients' in predicate:
queryset = queryset.filter(users__uuid__in=predicate['recipients'])
return queryset
这是我的api.py,我刚刚在其中将这个新的过滤器后端添加到列表中。
api.py
class MyViewSet(
MultipleSerializerMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet
):
...
filter_backends = [filters.BookingFilterBackend, filters. MyNewFilterBackend, DjangoFilterBackend, ]
...
# This is the api which receives filteration form data from frontend.
@list_route(methods=['POST'], url_path='export-bookings')
def export_bookings(self, request, *args, **kwargs):
queryset = self.get_queryset()
# filter results!
filtered_queryset = self.filter_queryset(queryset)
tasks.generate_export_data_and_notify_accounts(filtered_queryset)
return response.NoContent()
我仍然想知道是否可以使用FilterSets实现这一目标。