Использование __in для пользовательского запроса в django-фильтрах - PullRequest
0 голосов
/ 07 ноября 2018

Я использую django-фильтры 1.1.0. Мне нужно написать фильтр, который использует пользовательский запрос, но в котором он может дополнительно принимать суффикс __in.

Это мое решение, но я не могу не надеяться, что есть немного более чистый способ сделать это подобно тому, как указано id - возможно, используя единственный метод для бара и 'exact' или '__in' передается в качестве поискового аргумента.

class FooFilter(filters.FilterSet):

    bar_id = filters.CharFilter(method='filter_bar_id', label='Bar')
    bar_id__in = filters.CharFilter(method='filter_bar_id__in', label='Bar In')


    def filter_bar_id(self, queryset, name, value):
        return queryset.filter(
            Q(abc__xyz__bar=value) |
            Q(def__xyz__bar=value)).distinct()

    def filter_bar_id__in(self, queryset, name, value):
        bars = value.split(',')
        return queryset.filter(
            Q(abc__xyz__bar__in=bars) |
            Q(def__xyz__bar__in=bars)).distinct()

    class Meta:
        model = Foo
        fields = {
            'id': ['exact', 'in'],
            'bar_id': ['exact'],
            'bar_id__in': ['exact'],
        }

Есть ли у django-фильтров способ сделать это более естественным образом? Или это в значительной степени способ сделать это?

Есть еще один вопрос о стеке потока, который использует bar_id=, чтобы разрешить как ?bar_id=1, так и ?bar_id=1,2,3,4. Ради согласованности с остальными моими django-фильтрами (такими как ?id и ?id__in, я не заинтересован в этом.

1 Ответ

0 голосов
/ 09 декабря 2018

Вы можете использовать логику проверки BaseInFilter, которая преобразует входное значение через запятую в список значений. Оттуда ваш собственный метод фильтрации может переключаться в зависимости от типа значения.

Тем не менее, я не думаю, что это решение обязательно превосходит то, что у вас есть в настоящее время. Кроме того, это обычно не работает с дополнительными поисковыми выражениями. В этом случае вы можете включить только тип.

class CharListFilter(filters.BaseInFilter, filters.CharFilter):
    pass


class FooFilter(filters.FilterSet):
    bar_id = filters.CharFilter(method='filter_bar_id', label='Bar')
    bar_id__in = filters.CharListFilter(method='filter_bar_id', label='Bar In')

    def filter_bar_id(self, queryset, name, value):
        if isinstance(value, list):
            return queryset.filter(
                Q(abc__xyz__bar__in=value) |
                Q(def__xyz__bar__in=value)).distinct()
        return queryset.filter(
            Q(abc__xyz__bar=value) |
            Q(def__xyz__bar=value)).distinct()
...