親愛なるみんな、
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
ですが、バニラ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ではありません)。 このようなものが機能する可能性があります: