¿Cómo se filtra por un rango O un valor “null”? (Es decir, combinar el rango de filtro de número y el filtro booleano para null=True en un campo IntegerField)
Tengo un modelo Item
con un campo numérico number
. Este campo number
tiene un valor predeterminado de null.
models.py
class Item(models.Model):
number = models.IntegerField(default=None, blank=True, null=True)
Quiero configurar filtros que puedan devolver un conjunto de consultas de Items
donde el campo number
esté en un rango, lo cual es bastante sencillo:
filters.py
class ItemFilter(django_filters.FilterSet):
min_num = django_filters.NumberFilter(method="min_num_filter")
max_num = django_filters.NumberFilter(method="max_num_filter")
class Meta:
model = Item
fields = ("min_num", "max_num", "incl_null")
def min_num_filter(self, queryset, name, value):
return queryset.filter(number__gte=value)
def max_num_filter(self, queryset, name, value):
return queryset.filter(number__lte=value)
Pero, ¿qué sucede si quiero tener un filtro adicional de tipo booleano que incluya Items
que tengan null
para el campo number
, junto con cualquier Item
que coincida con el rango de min_num
y max_num
?
Por ejemplo, una consulta de URL en forma de ?min_num=1&max_num=10&incl_null=True
debería devolver todos los Items
donde el campo number
esté entre 1
y 10
, O donde el campo number
sea igual a None
.
El siguiente código no funciona:
class ItemFilter(django_filters.FilterSet):
...
incl_null = django_filters.BooleanFilter(method="incl_null_filter")
class Meta:
model = Item
fields = ("min_num", "max_num", "incl_null")
# no funciona
def incl_null_filter(self, queryset, name, value):
if value is True:
return queryset | Item.objects.filter(number=None)
if value is False:
return queryset
Edit: He intentado los métodos en la documentación de “Filtrado por valores vacíos”, pero creo que eso es exclusivamente para valores null
, donde estoy buscando una coincidencia de rango O un valor null
.
davy.ai
Para agregar un filtro booleano adicional que incluya
Items
connull
paranumber
, puedes modificar los métodosmin_num_filter
ymax_num_filter
en la claseItemFilter
de la siguiente manera:Aquí, hemos agregado un objeto
Q
al filtro paranumber
con un operadorOR
que incluye valoresnull
si el valor booleanoincl_null
esTrue
. Se accede al atributocleaned_data
para asegurarse de que el valor del filtroincl_null
se considere en los filtrosmin_num
ymax_num
. El métodoincl_null_filter
simplemente devuelve el conjunto de resultados sin cambios.Con estas modificaciones, una consulta de URL en forma de
?min_num=1&max_num=10&incl_null=True
debería retornar todos losItems
dondenumber
está entre1
y10
Onumber
es igual aNone
.