Django-filter' __ in'抬头

时间:2013-08-02 12:09:38

标签: python django

我正在使用带有https://github.com/alex/django-filter/的django-rest-framework,但问题主要是关于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')

我不能像这样使用网址

  

/ V1 /书籍/?id__in = 1,2,3

查找ID为1,2或3的图书

9 个答案:

答案 0 :(得分:6)

本期讨论的问题是: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

答案 1 :(得分: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

答案 2 :(得分:3)

django过滤器提供BaseInFilter以便与其他过滤器类(例如NumberFilterCharFilter)结合使用。此类仅验证传入请求为comma-separated。因此,如果您使用的是Web Browsable API,则可以/ book /?id__in = 1 %2C 3的形式发送请求,其中%2C是逗号。

filters.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")

views.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

答案 3 :(得分:1)

为您的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

希望能有所帮助。 THX。

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

不确定是否曾经回答过: 尝试: id = [1、2、3]用于数字 name = [“ name1”,“ name2”]用于字符串

答案 7 :(得分:0)

我刚刚在DjangoFilterBackend with multiple ids中回答了相同的问题

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

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

现在,您应该可以按get参数中的ID列表进行过滤,例如/v1/books/?id__in=1,2,3

答案 8 :(得分:-1)

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

您必须创建自定义视图:

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中为此视图添加一个条目。

然后尝试使用参数?ids=1_2_3

对您的网址发出GET请求