Estimados,
¿Existe una opción para establecer el campo de filtro predeterminado y el valor para usar si no se ha encontrado ningún parámetro que defino en Meta.fields en el objeto de solicitud?
Si no existe esa opción, ¿cuál sugeriría como la mejor manera de hacerlo?
Saludos,
Andrius
Hola @ andrius-senulis. django-filter está construido sobre los formularios normales de django, por lo que esta pregunta se puede resumir en "¿Cómo proporciono valores de campo predeterminados para formularios enlazados?" Según esta respuesta SO, puede agregar un método clean_<field_name>
a su formulario para proporcionar un valor predeterminado. Desafortunadamente, la clase de formulario subyacente no está expuesta directamente, por lo que no puede subclasificarla y agregar ese método (ver editar). Dicho esto, los filtros tienen un campo de formulario subyacente, por lo que puede subclasificar el campo y anular su método clean()
. Esto es un poco engorroso. p.ej,
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')
...
Un método más sencillo sería simplemente inspeccionar los datos entrantes y establecer un valor predeterminado.
def your_view(request):
data = request.GET.copy()
data.setdefault('some_field', 'some_value')
f = YourFilterSet(data, queryset=YourModel.objects.all())
...
editar:
De hecho, puede proporcionar un formulario base al FilterSet.Meta
, que luego se subclasifica internamente. Entonces, clean_<field name>
es posible.
class MyForm(forms.Form):
clean_some_field(self, value):
...
class MyFilterSet(FilterSet):
class Meta:
model = MyModel
form = MyForm
fields = ['some_field']
Yo uso FilterView. Anular get_filterset_kwargs funciona para mí:
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
Editar: cuando se usa, por ejemplo, la paginación, esto no se aplica (los datos b / c no son Ninguno). Algo como esto podría funcionar:
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
Usar __init__
funcionó para mí. (Esto es con djangorestframework-filters
, pero creo que es lo mismo que vainilla 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)
el método con __init__
no se recomienda y la solución alternativa documentada en el enlace no funcionó para mí ... https://django-filter.readthedocs.io/en/master/guide/tips.html #utilizando -valores-iniciales-como-valores-predeterminados
get_filterset_kwargs
en el FilterView
funcionó para mí.
no se recomienda el método con
__init__
En general, no se recomienda proporcionar valores predeterminados de formulario / filtro, ya que es una mala práctica que puede tener efectos confusos / adversos. Implementar a través de __init__
o cualquier otro método está bien (dado que está de acuerdo con los efectos).
Yo uso FilterView. Anular get_filterset_kwargs funciona para mí:
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
Editar: cuando se usa, por ejemplo, la paginación, esto no se aplica (los datos b / c no son Ninguno). Algo como esto podría funcionar:
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
¡Me has alegrado el día!
Comentario más útil
Yo uso FilterView. Anular get_filterset_kwargs funciona para mí:
Editar: cuando se usa, por ejemplo, la paginación, esto no se aplica (los datos b / c no son Ninguno). Algo como esto podría funcionar: