Создайте URL-адрес запроса для многократной фильтрации набора запросов Django по одному и тому же полю. - PullRequest
0 голосов
/ 30 августа 2018

Я хочу отфильтровать набор запросов Django по одному и тому же полю несколько раз, используя Q, чтобы включить / исключить записи с определенным значением в этом поле.

Я буду использовать пример модели, чтобы проиллюстрировать мой случай. Скажем, у меня есть модель Record с полем status. Это поле может быть одним из трех состояний A, B, C.

class Record(models.Model):
    STATUS_A = 'A'
    STATUS_B = 'B'
    STATUS_C = 'C'

    SOME_STATUSES = (
        (STATUS_A, 'Something A'),
        (STATUS_B, 'Something B'),
        (STATUS_C, 'Something C'),
    )

    status = models.CharField(
    max_length=1,
    choices= SOME_STATUSES,
    default= STATUS_A,
    )

У меня есть DRF ViewSet, который отвечает за возвращение отфильтрованного набора запросов Record объектов.

Прямо сейчас я фильтрую запрос, заданный одним состоянием, поэтому мой URL выглядит примерно так:

.../?status=A
.../?status=B
.../?status=C

Но скажем, я хочу отфильтровать набор запросов по нескольким статусам: Вернуть все записи со статусами A и B. Или вместо этого я хочу вернуть все записи, кроме тех, которые имеют статус C. Я не уверен, как создать URL в этих случаях. Я знаю, что дублирование параметров в URL - очень плохая практика:

.../?status=A&status=B

Как сделать один запрос A AND B или NOT C?

Остальная часть вопроса о том, как обрабатывать эти множественные значения, неясна, вероятно, потому, что я не понимаю, как построить такой запрос.

1 Ответ

0 голосов
/ 06 сентября 2018

Написав CustomDjangoFilter, вы можете достичь этого.

Пример кода

Примеры URL и их использование

URL  : localhost:8000/records/?status_include=A,B
URL  : localhost:8000/records/?status_exclude=A
URL  : localhost:8000/records/?status_include=A,B,C&status_exclude=D,E,F

Фрагмент кода

views.py

from django_filters.rest_framework import DjangoFilterBackend
from .filters import CustomRecordFilter

class RecordViewSet(viewsets.ModelViewSet):
    queryset = Record.objects.all()
    serializer_class = RecordSerializer

    # django-filter-backend and custom-filter-class
    filter_backends = (DjangoFilterBackend, )
    filter_class = CustomRecordFilter

filters.py

import django_filters

class CustomRecordFilter(django_filters.FilterSet):
    status_exclude = django_filters.CharFilter(field_name='status', method='filter_status_exclude')
    status_include = django_filters.CharFilter(field_name='status', method='filter_status_include')

def filter_status_include(self, queryset, name, value):
    if not value:
        return queryset
    values = ''.join(value.split(' ')).split(',')
    queryset = queryset.filter(status__in=values)
    return queryset

def filter_status_exclude(self, queryset, name, value):
    if not value:
        return queryset
    values = ''.join(value.split(' ')).split(',')

    # exclude status
    queryset = queryset.exclude(status__in=values)
    return queryset

class Meta:
    model = UserRoleGroup
    fields = ('status', 'status_include', 'status_exclude')
...