簡體   English   中英

如何在 django_filter 中使用選擇字段值過濾對象

[英]How to filter an object with choice filed values in django_filter

我的模型 IPInfo 中有以下選擇字段

class IPInfoModel(models.Model):
    TYPE_INTRANET = 1
    TYPE_INTERNET = 2
    IP_TYPES = (
        (TYPE_INTRANET, u'INTRANET'),
        (TYPE_INTERNET, u'INTERNET'),
    )
    ip = models.GenericIPAddressField("IP", unique=True)
    ip_type = models.SmallIntegerField(choices=IP_TYPES)

我使用 django_filters 來過濾 IPInfo。

from django_filters import rest_framework as django_filters 

class IPInfoFilter(django_filters.FilterSet):
    ip_type = django_filters.ChoiceFilter(choices=IPInfoModel.IP_TYPES)

    class Meta:
        model = IPInfoModel
        fields = ["ip_type",]


class IPInfoViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = IPInfoModel.objects.all()
    serializer_class = IPInfoSerializer
    filter_class = IPInfoFilter

我想過濾 ip_type 上的 IPInfo。 如何通過“INTRANET”或“INTERNET”過濾 IPInfo。 不要使用“1”或“2”。

您可以定義用於過濾的自定義方法

class IPInfoFilter(django_filters.FilterSet):
    ip_type = django_filters.CharFilter(method='filter_ip_type')


    def filter_ip_type(self, queryset, name, value):
        # create a dictionary string -> integer
        value_map = {v: k for k, v in IPInfoModel.IP_TYPES.items()}
        # get the integer value for the input string
        value = value_map[value]
        return queryset.filter(ip_type=value)

你可以使用這樣的東西來過濾多個選擇字段嗎:

models.py

from django.db import models

class MyModel(models.Model):
    class Options(models.IntegerChoices):
        OPTION_A = 1, 'FIRST'
        OPTION_B = 2, 'SECOND'
        OPTION_C = 3, 'THIRD'
    
    option = models.PositiveSmallIntegerField(
        verbose_name='Option',
        choices=Options.choices, 
        null=False, default=0,
    )

views.py

from rest_framework import viewsets

from .filters import MyFilter
from .models import MyModel
from .serializers import MySerializer


class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
    filter_backends = (MyFilter,)

serializers.py

from rest_framework import serializers

from .models import MyModel


class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = '__all__'

filters.py

import operator
from functools import reduce
from django.db.models import Q
from rest_framework.filters import BaseFilterBackend


def get_option_value(option):
    ''' Returns the option value '''
    # avoid circular import
    from .models import MyModel

    options = {
        MyModel.Options.OPTION_A.label: MyModel.Options.OPTION_A.value,
        MyModel.Options.OPTION_B.label: MyModel.Options.OPTION_B.value,
        MyModel.Options.OPTION_C.label: MyModel.Options.OPTION_C.value,
    }

    return options.get(option.upper(), None)


class MyFilter(BaseFilterBackend):
    ''' Filter by option label '''
    def filter_queryset(self, request, queryset, view):
        option_list = request.GET.getlist('option', None)
        
        if not option_list:
            return queryset.all()

        else:
            try:
                queries = []
                for option in option_list:
                    value = get_option_value(option)
                    if value:
                        queries.append(Q(option=value))
                return queryset.filter(reduce(operator.or_, queries))
            except Exception:
                return queryset.none()

使用上面的配置,創建一個到MyViewSet類的路由,然后運行:

python manage.py runserver

然后,在您的瀏覽器中訪問例如:

http://localhost:8000/my-view-set-url/?option=FIRST&option=THIRD

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM