17

我在django-filter包中使用 Django REST 框架,但我的问题主要是关于django-filter. 我不明白如何使用带有“__in”查找的过滤器。

例如我有以下模型:

class Book(models.Model):
   name = models.CharField(max_length=100)

class BookView(viewsets.ReadOnlyModelViewSet):
   serializer_class = BookSerializer()
   model = Book
   filter_fields = ('id', 'name')

而且我不能使用 URL/v1/books/?id__in=1,2,3来查找 ID 为 1、2 或 3 的书籍。

你如何使用 Django-filter 的 '__in' 查找?

4

9 回答 9

9

现在有一个简单的解决方案django_filter

class BookView(viewsets.ReadOnlyModelViewSet):
   serializer_class = BookSerializer()
   model = Book
   filter_fields = {
      'id': ['exact', 'in'],
      'name': ['exact']
   }

然后您可以完全按照您的需要在查询字符串中使用它:?id__in=1,2,3.

于 2020-01-30T15:04:35.730 回答
6

django-filter 提供BaseInFilter与其他过滤器类一起使用,例如NumberFilter, CharFilter. 此类仅验证传入请求是.因此comma-separated,如果您使用 Web Browsable API,则可以将请求发送为 /book/?id__in=1 %2C3%2C逗号在哪里。

过滤器.py

import django_filters


class NumberInFilter(django_filters.BaseInFilter, django_filters.NumberFilter):
    pass


class BookFilter(django_filters.FilterSet):
    id__in = NumberInFilter(field_name="id", lookup_expr="in")

视图.py

from rest_framework import viewsets
from django_filters import rest_framework as filters

from book.filters import BookFilter
from book.models import Book
from book.serializers import BookSerializer


class BookViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    filter_backends = (filters.DjangoFilterBackend, )
    filterset_class = BookFilter
    serializer_class = BookSerializer
于 2019-08-02T08:12:36.080 回答
5

这个问题讨论了这个问题:https ://github.com/alex/django-filter/issues/137#issuecomment-77697870

建议的解决方案是创建一个自定义过滤器,如下所示:

from django_filters import Filter
from django_filters.fields import Lookup

from .models import Product

class ListFilter(Filter):
    def filter(self, qs, value):
        value_list = value.split(u',')
        return super(ListFilter, self).filter(qs, Lookup(value_list, 'in'))

class ProductFilterSet(django_filters.FilterSet):
    id = ListFilter(name='id')

    class Meta:
        model = Product
        fields = ['id']

您可以编写以下内容:

产品/?id=7,8,9

于 2015-07-14T16:37:29.403 回答
3

django-filter 的文档很少。您可以尝试创建自定义过滤器并指定查找类型。它相当复杂:

class BookFilter(django_filters.FilterSet):
    id = django_filters.NumberFilter(name="id", lookup_type="in")

    class Meta:
        model = Book
        fields = ['id']

然后修改您的视图以使用过滤器类:

class BookView(viewsets.ReadOnlyModelViewSet):
    serializer_class = BookSerializer()
    model = Book
    filter_fields = ('id', 'name')
    filter_class = BookFilter

然后,您将能够通过它们的 ID 查找书籍(注意未使用“__in”):

/v1/books/?id=1,2,3
/v1/books/?id=1
于 2014-04-08T06:06:16.020 回答
2

为您的 id 字段(AutoField)自定义 PKsField 和 PKsFilter,然后查询参数将起作用:'/v1/books/?id__in=1,2,3'

from django.forms import Field
from django_filters.filters import Filter
from django.db.models import AutoField


class PKsField(Field):

    def clean(self, value): # convert '1,2,3' to {1, 2, 3}
        return set(int(v) for v in value.split(',') if v.isnumeric()) if value else ()


class PKsFilter(Filter):
    field_class = PKsField


class BookFilter(FilterSet):
    # ids = PKsFilter(name='id', lookup_type="in") # another way, query string: ?ids=1,2,3

    filter_overrides = {
        AutoField: {
            'filter_class': PKsFilter, # override default NumberFilter by the PKsFilter
            'extra': lambda f: {
                'lookup_type': 'in',
            }
        }
    }

    class Meta:
        model = Book
        fields = {
            'id': ('in',),
        }


from rest_framework import viewsets


class BookView(viewsets.ModelViewSet):
    queryset = ...
    serializer_class = ...
    filter_class = BookFilter

希望能有所帮助。谢谢。

于 2015-01-28T03:45:37.780 回答
0

不确定是否曾经回答过:尝试:id=[1, 2, 3] for numbers name=["name1", "name2"] for strings

于 2019-02-28T23:44:14.733 回答
0

相反/v1/books/?id__in=1,2,3,您可以使用/v1/books/?id=1&id=2&id=3

于 2017-07-05T10:56:05.083 回答
0

我刚刚在DjangoFilterBackend 中用多个 id回答了同样的问题

对于您的情况,这应该可以工作,而无需编写任何逻辑。

from django_filters import rest_framework as filters

class NumberInFilter(filters.BaseInFilter, filters.NumberFilter):
    pass


class BookFilter(filters.FilterSet):
    id_in = NumberInFilter(field_name='id', lookup_expr='in')

    class Meta:
        model = Book
        fields = ['id_in', 'name']

class BookView(viewsets.ReadOnlyModelViewSet):
   serializer_class = BookSerializer()
   model = Book
   filter_class = BookFilter

现在您应该能够通过获取参数中的 id 列表进行过滤,例如/v1/books/?id__in=1,2,3

于 2019-05-07T15:17:56.180 回答
-1

django 管理站点仅在模板 app_name/model_name/primary_key 下创建 url 来编辑模型的实例。它不提供__in通过 URL 的过滤。

您必须创建一个自定义视图:

def myview(request):
    # you can get parameters from request.GET or request.POST
    selected_books = None
    if request.method = "POST":
        ids = request.POST["ids"].split("_")
        selected_books = Book.objects.filter(id__in=ids)

    return render_to_response('mytemplate.html', { 'selected_books': selected_books }, context_instance = RequestContext(request) )

在 mytemplate.html 中:

{% for entry in selected_books %}
  ... {{ entry }} ...
{% endfor %}

在 urls.py 中向该视图添加一个条目。

然后尝试使用参数向您的 URL 发出 GET 请求?ids=1_2_3

于 2013-08-02T12:40:50.963 回答