构建请求 URL 以通过同一字段多次过滤 Django 查询集

Posted

技术标签:

【中文标题】构建请求 URL 以通过同一字段多次过滤 Django 查询集【英文标题】:Build request URL to filter Django queryset multiple times by the same field 【发布时间】:2019-02-05 07:04:30 【问题描述】:

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

我将使用示例模型来说明我的案例。假设我有一个带有字段statusRecord 模型。该字段可以是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

如何请求AANDBNOTC

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

【问题讨论】:

你能分享ViewSet代码吗? DRF 对成员资格检查有一些支持。 @WillemVanOnsem 它相当庞大,因为实际的 ViewSet 过滤了具有多个不同参数的查询,并且我正在使用多个 Mixin 来保持秩序。我将尝试将其最小化以适应问题并在今天晚些时候上传。但主要是我的问题是如何建立这样的网址。 相关:***.com/q/18016543/67579 我认为您应该在查询字符串上发送array,然后在后端进行过滤。 .../?status=[A,B,C]。也尝试使用django-filters /?status_must=A,B&status_mustnot=C 这是您预期的网址吗? 【参考方案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')

【讨论】:

以上是关于构建请求 URL 以通过同一字段多次过滤 Django 查询集的主要内容,如果未能解决你的问题,请参考以下文章

我们可以使用不同的过滤条件在同一个表字段或列上多次使用相同的聚合函数吗?

OData:通配符(startswith)过滤 url 请求中的数字(ID)字段

如何通过 URL 将变量过滤器添加到 Drupal 6 视图?

防止 Django 在并发请求时将同一个对象多次保存到数据库中

Thymeleaf URL 构建

爬虫的总结 私人日志