django filter查询不到报啥错

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django filter查询不到报啥错相关的知识,希望对你有一定的参考价值。

参考技术A filter如果查询不到,不会报错,返回的数据长度为0.

Django-filters:单个查询字符串中的多个 ID

【中文标题】Django-filters:单个查询字符串中的多个 ID【英文标题】:Django-filters: multiple IDs in a single query string 【发布时间】:2018-11-20 19:16:44 【问题描述】:

使用django-filters,我看到了有关如何在单个查询字符串中提交多个相同类型的参数的各种解决方案,例如多个ID。他们都建议使用包含逗号分隔值列表的单独字段,例如:

http://example.com/api/cities?ids=1,2,3

是否有使用单个参数但提交一次或多次的通用解决方案?例如:

http://example.com/api/cities?id=1&id=2&id=3

我尝试使用 MultipleChoiceFilter,但它希望定义实际选择,而我想传递任意 ID(其中一些 ID 甚至可能不存在于数据库中)。

【问题讨论】:

有些甚至不存在于数据库中是什么意思?那应该怎么办? @WillemVanOnsem 应该使用标准的 IN 查找。如果您请求 id=1&id=2 并且 ID 为 2 的资源不存在,则结果列表中只会返回第一个。如果两者都不存在,则会返回一个空列表。 这能回答你的问题吗? How do you use the django-filter package with a list of parameters? 【参考方案1】:

这是一个可重复使用的解决方案,使用自定义 Filter 和自定义 Field

自定义的Field 重用了Django 的MultipleChoiceField,但替换了验证函数。 相反,它使用我们传递给构造函数的另一个 Field 类进行验证。

from django.forms.fields import MultipleChoiceField

class MultipleValueField(MultipleChoiceField):
    def __init__(self, *args, field_class, **kwargs):
        self.inner_field = field_class()
        super().__init__(*args, **kwargs)

    def valid_value(self, value):
        return self.inner_field.validate(value)

    def clean(self, values):
        return values and [self.inner_field.clean(value) for value in values]

自定义Filter 使用MultipleValueField 并转发field_class 参数。 它还将lookup_expr 的默认值设置为in

from django_filters.filters import Filter

class MultipleValueFilter(Filter):
    field_class = MultipleValueField

    def __init__(self, *args, field_class, **kwargs):
        kwargs.setdefault('lookup_expr', 'in')
        super().__init__(*args, field_class=field_class, **kwargs)

要使用此过滤器,只需使用适当的field_class 创建一个MultipleValueFilter。例如,要通过id 过滤City,我们可以使用IntegerField,如下所示:

from django.forms.fields import IntegerField

class CityFilterSet(FilterSet):
    id = MultipleValueFilter(field_class=IntegerField)
    name = filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = City
        fields = ['name']

【讨论】:

感谢您。我已经发布了一项改进,以允许诸如 iexact 之类的lookup_exprs。 ***.com/a/68162262/1321009【参考方案2】:

受 Jerin 的回答启发,使用自定义过滤器解决:

class ListFilter(Filter):
    def filter(self, queryset, value):
        try:
            request = self.parent.request
        except AttributeError:
            return None

        values = request.GET.getlist(self.name)
        values = int(item) for item in values if item.isdigit()

        return super(ListFilter, self).filter(queryset, Lookup(values, 'in'))

如果值是非数字的,例如color=blue&color=red 那么isdigit() 验证当然是没有必要的。

【讨论】:

这对我来说似乎很奇怪,这还不是 django-filters 中的默认行为......这是一个常见的用例。【参考方案3】:

作为选项

class CityFilterSet(django_filters.FilterSet):
    id = django_filters.NumberFilter(method='filter_id')

    def filter_id(self, qs, name, value):
        return qs.filter(id__in=self.request.GET.getlist('id'))

【讨论】:

【参考方案4】:

我建议您使用自定义过滤器,如下所示

from django_filters.filters import Filter
from rest_framework.serializers import ValidationError
from django_filters.fields import Lookup


class ListFilter(Filter):
    def filter(self, queryset, value):
        list_values = value.split(',')
        if not all(item.isdigit() for item in list_values):
            raise ValidationError('All values in %s the are not integer' % str(list_values))
        return super(ListFilter, self).filter(queryset, Lookup(list_values, 'in'))

【讨论】:

对,当你想将多个值作为ids=1,2,3 传递时,这就是解决方案,但我正在专门寻找如何处理同名的多个参数,所以id=1&id=2&id=3。跨度> 【参考方案5】:

我对@9​​87654321@ 有一些问题

所以我稍微改了一下:

class ListFilter(Filter):
    def __init__(self, query_param, *args, **kwargs):
        super(ListFilter, self).__init__(*args, **kwargs)
        # url = /api/cities/?id=1&id=2&id=3 or /api/cities/?id=1,2,3
        # or /api/cities/?id=1&id=2&id=3?id=4,5,6
        self.query_param = query_param 
        self.lookup_expr = 'in'

    def filter(self, queryset, value):
        try:
            request = self.parent.request
        except AttributeError:
            return None

        values = set()
        query_list = request.GET.getlist(self.query_param)
        for v in query_list:
            values = values.union(set(v.split(',')))
        values = set(map(int, values))

        return super(ListFilter, self).filter(queryset, values)
class CityFilter(filterset.FilterSet):
    id = ListFilter(field_name='id', query_param='id')
    name = filters.CharFilter(field_name='name', lookup_expr='icontains')

    class Meta:
        model = City
        fields = ['name']

如果您想使用自定义查询参数名称 - 更改 query_param arg。

【讨论】:

【参考方案6】:

Benoit Blanchon 是 imo 最好的

但我已尝试对其进行改进以允许更多类型的lookup_expr。 完整代码 sn-ps 见他的answer。

from django.db.models import Q

class MultipleValueFilter(Filter):
    field_class = MultipleValueField

    def __init__(self, *args, field_class, **kwargs):
        kwargs.setdefault('lookup_expr', 'in')
        super().__init__(*args, field_class=field_class, **kwargs)

    def filter(self, qs, value):
        # if it's not a list then let the parent deal with it
        if self.lookup_expr == 'in' or not isinstance(value, list):
            return super().filter(qs, value)

        # empty list
        if not value:
            return qs
        if self.distinct:
            qs = qs.distinct()

        lookup = '%s__%s' % (self.field_name, self.lookup_expr)
        filters = Q()
        for v in value:
            filters |= Q(**lookup: v)
        qs = self.get_method(qs)(filters)
        return qs

通过此更改,您现在可以使用 iexact 了。 您也可以使用 gte 等,但这些可能没有多大意义。

【讨论】:

【参考方案7】:

http://example.com/api/cities?ids=1,2,3

get_ids=1,2,3
id_list = list(get_ides]
Mdele_name.objects.filter(id__in= id_list)

【讨论】:

以上是关于django filter查询不到报啥错的主要内容,如果未能解决你的问题,请参考以下文章

django-admin 仿写stark组件action,filter筛选过滤,search查询

django怎么判断数据库的记录是不是存在

Djang DJANGO_SETTINGS_MODULE

Django框架-- Djang与Ajax

创建djang+vue项目

Django找不到模板(templates)文件的解决办法