构建请求URL以按同一字段多次过滤Django queryset

时间:2018-08-30 10:53:38

标签: python django django-rest-framework django-q

我想使用Q通过同一字段多次过滤Django queryset,以在该字段中包含/排除具有特定值的记录。

我将使用示例模型来说明我的情况。假设我有一个Record字段为status的模型。此字段可以是三个状态ABC之一。

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

但是说我想按多种状态过滤查询集: 返回状态为AB的所有记录。 或者,我想返回除状态为C以外的所有记录。在这种情况下,我不确定如何构建URL。我知道在URL中复制参数是一种非常不好的做法:

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

一个请求如何A AND BNOT C

如何处理这些多个值的问题的其余部分尚不清楚,可能是因为我一开始并不了解如何构建这样的查询。

1 个答案:

答案 0 :(得分:1)

通过编写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')
相关问题