Приветствую всех,
Есть ли возможность установить поле фильтра по умолчанию и значение для использования, если в объекте запроса не найден параметр, который я определяю в Meta.fields?
Если такой возможности нет, что бы вы посоветовали сделать лучше всего?
С уважением,
Андрюс
Привет @ 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
Вы сделали мой день!
Самый полезный комментарий
Я использую FilterView. У меня работает переопределение get_filterset_kwargs:
Изменить: при использовании, например, разбивки на страницы, это не применяется (данные b / c не являются None). Что-то вроде этого может сработать: