Django-filter: Фильтрация по умолчанию, если в запросе не переданы параметры фильтра.

Созданный на 6 нояб. 2015  ·  6Комментарии  ·  Источник: carltongibson/django-filter

Приветствую всех,

Есть ли возможность установить поле фильтра по умолчанию и значение для использования, если в объекте запроса не найден параметр, который я определяю в Meta.fields?

Если такой возможности нет, что бы вы посоветовали сделать лучше всего?

С уважением,
Андрюс

Самый полезный комментарий

Я использую FilterView. У меня работает переопределение get_filterset_kwargs:

class MyFilterView(FilterView):
    filterset_class = filters.MyFilter
    # ...
    def get_filterset_kwargs(self, filterset_class):
        kwargs = super(MyFilterView, self).get_filterset_kwargs(filterset_class)
        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        return kwargs

Изменить: при использовании, например, разбивки на страницы, это не применяется (данные b / c не являются None). Что-то вроде этого может сработать:

        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        elif "is_very_interesting" not in kwargs["data"]:
            kwargs["data"] = kwargs["data"].copy()
            kwargs["data"]["is_very_interesting"] = False

Все 6 Комментарий

Привет @ andrius-senulis. django-filter построен на основе обычных форм django, поэтому этот вопрос можно свести к следующему: «Как мне предоставить значения полей по умолчанию для связанных форм?» В соответствии с этим SO- ответом вы можете добавить в свою форму метод clean_<field_name> , чтобы предоставить значение по умолчанию. К сожалению, базовый класс формы не отображается напрямую, поэтому вы не можете создать его подкласс и добавить этот метод (см. "Правка"). Тем не менее, фильтры имеют базовое поле формы, поэтому вы можете создать подкласс этого поля и переопределить его метод clean() . Это немного громоздко. например,

class DecimalDefaultField(forms.DecimalField):
    def clean(self, value):
        if value is None:
            return 4.0
        return super(DecimalDefaultField, self).clean(value)

class NumberDefaultFilter(filters.NumberFilter):
    field_class = DecimalDefaultField

class MyFilterSet(FilterSet):
    some_field = NumberDefaultFilter(name='some_field')
    ...

Более простой способ - просто проверить входящие данные и установить значение по умолчанию.

def your_view(request):
    data = request.GET.copy()
    data.setdefault('some_field', 'some_value')

    f = YourFilterSet(data, queryset=YourModel.objects.all())
    ...

редактировать:
Фактически вы можете предоставить базовую форму для FilterSet.Meta , которая затем будет разделена на внутренние подклассы. Итак, clean_<field name> возможно.

class MyForm(forms.Form):
    clean_some_field(self, value):
        ...

class MyFilterSet(FilterSet):
    class Meta:
        model = MyModel
        form = MyForm
        fields = ['some_field']

Я использую FilterView. У меня работает переопределение get_filterset_kwargs:

class MyFilterView(FilterView):
    filterset_class = filters.MyFilter
    # ...
    def get_filterset_kwargs(self, filterset_class):
        kwargs = super(MyFilterView, self).get_filterset_kwargs(filterset_class)
        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        return kwargs

Изменить: при использовании, например, разбивки на страницы, это не применяется (данные b / c не являются None). Что-то вроде этого может сработать:

        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        elif "is_very_interesting" not in kwargs["data"]:
            kwargs["data"] = kwargs["data"].copy()
            kwargs["data"]["is_very_interesting"] = False

Использование __init__ сработало для меня. (Это с djangorestframework-filters , но я думаю, это то же самое, что и vanilla django-filter ):

class MyFilter(filters.FilterSet):
    foo = ...

    def __init__(self, data, *args, **kwargs):
        if not data.get('foo'):
            data = data.copy()
            data['foo'] = 'bar'
        super().__init__(data, *args, **kwargs)

метод с __init__ не рекомендуется, и обходной путь, описанный в ссылке, у меня не сработал ... https://django-filter.readthedocs.io/en/master/guide/tips.html # using -initial-values-as-defaults
get_filterset_kwargs в FilterView у меня сработало.

метод с __init__ не рекомендуется

Предоставление значений формы / фильтра по умолчанию в целом не рекомендуется, поскольку это плохая практика, которая может иметь запутанные / неблагоприятные последствия. Реализация с помощью __init__ или любого другого метода подойдет (при условии, что у вас все в порядке с эффектами).

Я использую FilterView. У меня работает переопределение get_filterset_kwargs:

class MyFilterView(FilterView):
    filterset_class = filters.MyFilter
    # ...
    def get_filterset_kwargs(self, filterset_class):
        kwargs = super(MyFilterView, self).get_filterset_kwargs(filterset_class)
        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        return kwargs

Изменить: при использовании, например, разбивки на страницы, это не применяется (данные b / c не являются None). Что-то вроде этого может сработать:

        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        elif "is_very_interesting" not in kwargs["data"]:
            kwargs["data"] = kwargs["data"].copy()
            kwargs["data"]["is_very_interesting"] = False

Вы сделали мой день!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги