11

我正在使用 Django REST 框架库,我正在尝试制作一个可以按 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 settings.py

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

我当前的请求 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**
4

5 回答 5

10

我通过像这样修改我的类 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

我的请求 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**&last_name=Tes**
于 2017-07-26T12:05:53.713 回答
5

我认为 DjangoFilterBackend 主要是基于平等的过滤。但您可以自定义过滤方式

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

于 2017-07-25T10:32:24.313 回答
5

我所做的是编写自定义 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 查询集字段查找(__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,不要包含可能导致相关用户模型的外键。

于 2018-06-21T08:57:46.513 回答
1

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

过滤器.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
    ...
于 2019-07-23T04:49:53.457 回答
0

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

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

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

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

于 2018-04-19T10:03:09.963 回答