Django过滤后端

时间:2017-07-25 07:43:25

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

我正在使用Django rest framework API,我试图通过first_name或last_name或两者来制作过滤器。 这是我的 ContactViewSet.py

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    filter_backends = (DjangoFilterBackend, )
    filter_fields = ('first_name', 'last_name')
    lookup_field = 'idContact'

我的DRF设置:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
}

我的执行请求网址如下:

http://localhost:8000/api/v1/contacts/?first_name=Clair&last_name=Test

但我正在寻找类似的东西:

http://localhost:8000/api/v1/contacts/?first_name=Cl**&last_name=Tes**

任何帮助将不胜感激..

5 个答案:

答案 0 :(得分:3)

我通过修改我的类ContactFilter解决了我的问题:

import django_filters
from .models import Contact

class ContactFilter(django_filters.FilterSet):
   class Meta:
        model = Contact
        fields = {
            'first_name': ['startswith'],
            'last_name': ['startswith'],
        }
        together = ['first_name', 'last_name']

在我看来,我必须这样做:

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    filter_class = ContactFilter

我的请求网址如下:

http://localhost:8000/api/v1/contact/?first_name__contains=Cl&last_name__contains=Tes

但我仍然想知道我是否可以在Django中使用这样的东西

http://localhost:8000/api/v1/contacts/?first_name=Cl**&last_name=Tes**

答案 1 :(得分:2)

我认为DjangoFilterBackend主要是基于等式的过滤。但你可以customize the filtering method

同样在DRF中,对于非精确过滤,有SearchFilter默认情况下会使用不区分大小写的部分匹配搜索。

答案 2 :(得分:1)

我要做的是编写自定义FilterBackend。像这样:

# views.py
from rest_framework import filters

class ObjektFilterBackend(filters.BaseFilterBackend):
    allowed_fields = ['objekt', 'naziv', 'kategorija', 'zadnja_sprememba']

    def filter_queryset(self, request, queryset, view):
        flt = {}
        for param in request.query_params:
            for fld in self.allowed_fields:
                if param.startswith(fld):
                    flt[param] = request.query_params[param]

        return queryset.filter(**flt)


class ObjektiViewSet(mixins.ListModelMixin,
                 mixins.RetrieveModelMixin,
                 viewsets.GenericViewSet):
    authentication_classes = (
        authentication.TokenAuthentication,
        authentication.SessionAuthentication)
    permission_classes = (IsAuthenticated,)
    queryset = models.Objekt.objects.all()
    serializer_class = serializers.ObjektSerializer
    filter_backends = (ObjektFilterBackend, ObjektOrderBackend,)
    ....

除了基本过滤(字段名=值对)之外,我还可以在URL中使用任何Django queryset Field Lookups(__ gt,__ gte,__ startswith等)。

http://localhost:8000/api/v2/objekti/?naziv__startswith=Apartma&zadnja_sprememba__gte=2018-01-01

并且ObjektFilterBackend类可以很容易地调整为支持按模式搜索。

仅需一点警告-这种方法具有潜在的危险,因为它允许最终用户也按外键字段进行过滤。这样的事情也可以:

http://localhost:8000/api/v2/objekti/?kategorija__naziv__icontains=sobe

因此,请谨慎地限制allowed_fields,不要包含可能导致相关用户模型的外键。

答案 3 :(得分:0)

如果您的要求不是太复杂,您也可以使用:

class YourModelViewSet(viewsets.ModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer
    filter_fields = {'some_field': ['startswith']}

这将在请求查询参数中启用'?some_field__starswith = text'sintax支持。

我认为'startswith'可以替换为任何django标准查询集过滤器参数。

答案 4 :(得分:0)

对于模糊搜索查询,我建议使用这种方法:

filters.py

from django_filters import rest_framework as filters
from django.db.models import Q
from . import models

def filter_name(queryset, name, value):
    """
    Split the filter value into separate search terms and construct a set of queries from this. The set of queries
    includes an icontains lookup for the lookup fields for each of the search terms. The set of queries is then joined
    with the OR operator.
    """
    lookups = [name + '__icontains', ]

    or_queries = []

    search_terms = value.split()

    for search_term in search_terms:
        or_queries += [Q(**{lookup: search_term}) for lookup in lookups]

    return queryset.filter(reduce(operator.or_, or_queries))


class ContactFilter(filters.FilterSet):
    first_name = filters.CharFilter(method=filter_name, name='first_name')
    last_name = filters.CharFilter(method=filter_name, name='last_name')

    class Meta:
        model = models.Contact
        fields = [
            'first_name',
            'last_name',
        ]

api.py

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    filter_class = ContactFilter
    ...