Hallo zusammen,
Gibt es eine Option, um das Standardfilterfeld und den zu verwendenden Wert festzulegen, wenn im Anforderungsobjekt kein Parameter gefunden wurde, den ich in den Meta.fields definiere?
Wenn es eine solche Option nicht gibt, was würden Sie als den besten Weg vorschlagen?
Grüße,
Andrius
Hallo @andrius-senulis. django-filter baut auf regulären django-Formularen auf, daher kann diese Frage in "Wie stelle ich Standardfeldwerte für gebundene Formulare bereit?" zusammengefasst werden. Gemäß dieser SO- Antwort können Sie Ihrem Formular eine clean_<field_name>
Methode hinzufügen, um einen Standardwert bereitzustellen. Leider wird die zugrunde liegende Formularklasse nicht direkt verfügbar gemacht, sodass Sie sie nicht unterklassen und diese Methode hinzufügen können (siehe Bearbeiten). Filter haben jedoch ein zugrunde liegendes Formularfeld, sodass Sie eine Unterklasse des Felds erstellen und seine Methode clean()
überschreiben können. Dies ist ein wenig umständlich. z.B,
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')
...
Eine einfachere Methode wäre, einfach die eingehenden Daten zu überprüfen und einen Standardwert festzulegen.
def your_view(request):
data = request.GET.copy()
data.setdefault('some_field', 'some_value')
f = YourFilterSet(data, queryset=YourModel.objects.all())
...
bearbeiten:
Sie sind tatsächlich in der Lage, FilterSet.Meta
eine Basisform bereitzustellen, die dann intern in Unterklassen unterteilt wird. Also, clean_<field name>
ist möglich.
class MyForm(forms.Form):
clean_some_field(self, value):
...
class MyFilterSet(FilterSet):
class Meta:
model = MyModel
form = MyForm
fields = ['some_field']
Ich verwende eine FilterView. Das Überschreiben von get_filterset_kwargs funktioniert bei mir:
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
Bearbeiten: Bei Verwendung von zB Paginierung wird dies nicht angewendet (b/c-Daten sind nicht None). So etwas könnte funktionieren:
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
Die Verwendung von __init__
hat bei mir funktioniert. (Dies ist mit djangorestframework-filters
, aber ich denke, es ist dasselbe wie Vanille 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)
die Methode mit __init__
wird nicht empfohlen und der im Link dokumentierte Workaround hat bei mir nicht funktioniert ... https://django-filter.readthedocs.io/en/master/guide/tips.html #using -initial-values-as-defaults
get_filterset_kwargs
im FilterView
hat bei mir funktioniert.
die Methode mit
__init__
wird nicht empfohlen
Die Bereitstellung von Standardformular-/Filterwerten im Allgemeinen wird nicht empfohlen, da dies eine schlechte Vorgehensweise ist, die verwirrende/nachteilige Auswirkungen haben kann. Die Implementierung über __init__
oder eine andere Methode ist in Ordnung (vorausgesetzt, Sie sind mit den Effekten einverstanden).
Ich verwende eine FilterView. Das Überschreiben von get_filterset_kwargs funktioniert bei mir:
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
Bearbeiten: Bei Verwendung von zB Paginierung wird dies nicht angewendet (b/c-Daten sind nicht None). So etwas könnte funktionieren:
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
Du hast meinen Tag gerettet!
Hilfreichster Kommentar
Ich verwende eine FilterView. Das Überschreiben von get_filterset_kwargs funktioniert bei mir:
Bearbeiten: Bei Verwendung von zB Paginierung wird dies nicht angewendet (b/c-Daten sind nicht None). So etwas könnte funktionieren: