代码之家  ›  专栏  ›  技术社区  ›  Stan Reduta

生成请求URL以按同一字段多次筛选Django queryset

  •  1
  • Stan Reduta  · 技术社区  · 6 年前

    我想用同一个字段多次过滤Django queryset 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 负责返回 记录 物体。

    URL 看起来像:

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

    但假设我想按多个状态过滤queryset: A B类 或者我想返回所有记录,除了那些状态为 C级

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

    A AND NOT C级 ?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Stan Reduta    6 年前

    通过编写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
    

    视图.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
    

    过滤器.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')