具有基于类的视图的Django过滤器:动态应用Django FilterSet

时间:2018-10-18 07:05:32

标签: django reactjs django-rest-framework django-filters

我正在使用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。我不知道我的过滤器逻辑是否正确编写。

2 个答案:

答案 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实现这一目标。