Django-фильтры: несколько идентификаторов в одной строке запроса - PullRequest
0 голосов
/ 11 июня 2018

Используя django-filters , я вижу различные решения о том, как передать несколько аргументов одного и того же типа в одной строке запроса, например, для нескольких идентификаторов.Все они предлагают использовать отдельное поле, которое содержит список значений, разделенных запятыми, например:

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

Существует ли общее решение для использования одного параметра, но оно отправляется один или несколько раз?Например:

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

Я пытался использовать MultipleChoiceFilter, но он ожидает, что будет определен фактический выбор, тогда как я хочу передать произвольные идентификаторы (некоторые из которых могут даже не существовать в БД).

Ответы [ 5 ]

0 голосов
/ 21 августа 2019

Как вариант

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'))

0 голосов
/ 24 июня 2019

У меня есть некоторые проблемы с этим решением

Поэтому я немного его изменил:

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 аргумент

0 голосов
/ 12 июня 2018

Решено с помощью пользовательского фильтра, вдохновленного ответом Джерина:

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(), конечно, не требуется.

0 голосов
/ 14 июня 2018

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)
0 голосов
/ 12 июня 2018

Я бы порекомендовал вам использовать пользовательский фильтр, как показано ниже

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'))
...