Python Django过滤器后端

Python Django过滤器后端,python,django,django-rest-framework,django-rest-swagger,Python,Django,Django Rest Framework,Django Rest Swagger,我正在使用Django rest框架API,我试图通过名字或姓氏或两者来制作一个过滤器。 这是我的联系人视图集.py: class ContactViewSet(viewsets.ModelViewSet): queryset = Contact.objects.all() serializer_class = ContactSerializer filter_backends = (DjangoFilterBackend, ) filter_fields = (

我正在使用Django rest框架API,我试图通过名字或姓氏或两者来制作一个过滤器。 这是我的联系人视图集.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',),
}
我的actuel请求url如下所示:

http://localhost:8000/api/v1/contacts/?first_name=Clair&last_name=Test
但我在找这样的东西:

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

任何帮助都将不胜感激。

我认为DjangoFilterBackend主要是基于平等的过滤。但是你可以


同样在DRF中,对于非精确过滤,有一个默认情况下不区分大小写的部分匹配搜索。我通过修改类ContactFilter解决了我的问题,如下所示:

# 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,)
    ....
http://localhost:8000/api/v2/objekti/?naziv__startswith=Apartma&zadnja_sprememba__gte=2018-01-01
导入django\u过滤器
从。模型导入联系人
类别ContactFilter(django_filters.FilterSet):
类元:
型号=触点
字段={
'名字':['startswith'],
'姓氏':['startswith'],
}
合在一起=['名字','姓氏']
在我看来,我必须这样做:

class ContactViewSet(ViewSet.ModelViewSet):
queryset=Contact.objects.all()
serializer\u class=ContactSerializer
filter\u class=ContactFilter
我的请求url如下所示:

http://localhost:8000/api/v1/contact/?first_name__contains=Cl&last_name__contains=Tes
但我还是想知道在Django能不能有这样的东西

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

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

class YourModelViewSet(viewsets.ModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer
    filter_fields = {'some_field': ['startswith']}
这将在请求查询参数中启用“?some_field_uustarswith=text”sintax支持


我想“startswith”可以替换为任何django standart queryset筛选器参数。

我要做的是编写自定义筛选器包。大概是这样的:

# 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,)
    ....
http://localhost:8000/api/v2/objekti/?naziv__startswith=Apartma&zadnja_sprememba__gte=2018-01-01
除了基本筛选(fieldname=值对),我还可以在我的URL中使用任何(_gt、_gte、_startswith…)如下所示:

# 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,)
    ....
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

因此,请仔细限制允许的_字段,不要包含可能导致相关用户模型的外键。

对于模糊搜索查找,我建议使用以下方法:

过滤器.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',
        ]
class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    filter_class = ContactFilter
    ...
api.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',
        ]
class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    filter_class = ContactFilter
    ...

无法测试此atm。。。
first\u name\u startswith=Cl
有用吗?。不,问题是我必须填写确切的first\u name来筛选如果你只对按查询参数筛选感兴趣,那么编写自定义管理器可以做任何你想做的事。我是Django的初学者,你能告诉我怎么做吗!谢谢你的重播!但是SearchFilter不允许我有这样的请求url:*&last_name=Tes**那么定制django filter的过滤可能是最好的方法,可以帮助你做到这一点,以及我在答案中链接的文档。请你看看下面的答案。谢谢不要为此写答案,请用新代码编辑您的问题。好的,谢谢,但您是否看到如何使用类似first\u name=val**的内容请注意,在filter\u字段中称为filterset\u字段。