如何按范围或 "null" 值过滤? (即结合 NumberFilter 范围和 BooleanFilter 为 null=True IntegerField)
How to filter by range OR "null" value? (I.e. combine NumberFilter range and BooleanFilter for null=True IntegerField)
我有一个带有数字 number
字段的 Item
模型。此 number
字段默认为空。
# models.py
class Item(models.Model):
number = models.IntegerField(default=None, blank=True, null=True)
我想设置可以 return Items
的查询集的过滤器,其中 number
在范围内 - 这很简单:
# 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)
但是,如果我想要一个额外的布尔过滤器,它可以包括 Items
,其中 null
用于 number
以及任何 Items
匹配 min_num
和 max_num
范围?
因此,例如,?min_num=1&max_num=10&incl_null=True
形式的 URL 查询应该 return 所有 Items
其中 number
在 1
之间10
OR number
等于 None
.
以下代码不起作用:
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")
// doesn't work
class incl_null_filter(self, queryset, name, value):
if value is True:
return queryset | Item.objects.filter(number=None)
if value is False:
return queryset
编辑: 我已经尝试了“Filtering by empty values”文档中的方法,但我认为那是专门针对 null
值的 - 我在这里寻找范围匹配 或 null
值。
嗯,我能想到的唯一解决方案是将最小范围、最大范围和 is_null 布尔值传递到单个 char
字段中,然后将其转换为 3 个单独的过滤器以进行操作.
所以查询 URL 看起来像 ?master_num=1-10-1
范围 1 - 10
incl。 None
和 ?master_num=1-10-0
范围 1 - 10
不包括。 None
.
class ItemFilter(django_filters.FilterSet):
master_num = django_filters.CharFilter(method="master_num_filter")
class Meta:
model = Item
fields = ("master_num")
def master_num_filter(self, queryset, name, value):
# array = [min, max, 1 or 0 for True and False]
array = value.split("-")
min = Q(year_published__gte=int(array[0]))
max = Q(year_published__lte=int(array[1]))
if array[2] == "1":
incl_null = Q(year_published=None)
return queryset.filter((min & max) | incl_null)
else:
return queryset.filter(min & max)
想知道是否有更好的方法。
试试这个查询:
from django.db.models import Q
min_ = 0
max_ = 10
Item.objects.filter(Q(number__gte=min_, number__lte=max_) | Q(number__isnull=True))
我有一个带有数字 number
字段的 Item
模型。此 number
字段默认为空。
# models.py
class Item(models.Model):
number = models.IntegerField(default=None, blank=True, null=True)
我想设置可以 return Items
的查询集的过滤器,其中 number
在范围内 - 这很简单:
# 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)
但是,如果我想要一个额外的布尔过滤器,它可以包括 Items
,其中 null
用于 number
以及任何 Items
匹配 min_num
和 max_num
范围?
因此,例如,?min_num=1&max_num=10&incl_null=True
形式的 URL 查询应该 return 所有 Items
其中 number
在 1
之间10
OR number
等于 None
.
以下代码不起作用:
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")
// doesn't work
class incl_null_filter(self, queryset, name, value):
if value is True:
return queryset | Item.objects.filter(number=None)
if value is False:
return queryset
编辑: 我已经尝试了“Filtering by empty values”文档中的方法,但我认为那是专门针对 null
值的 - 我在这里寻找范围匹配 或 null
值。
嗯,我能想到的唯一解决方案是将最小范围、最大范围和 is_null 布尔值传递到单个 char
字段中,然后将其转换为 3 个单独的过滤器以进行操作.
所以查询 URL 看起来像 ?master_num=1-10-1
范围 1 - 10
incl。 None
和 ?master_num=1-10-0
范围 1 - 10
不包括。 None
.
class ItemFilter(django_filters.FilterSet):
master_num = django_filters.CharFilter(method="master_num_filter")
class Meta:
model = Item
fields = ("master_num")
def master_num_filter(self, queryset, name, value):
# array = [min, max, 1 or 0 for True and False]
array = value.split("-")
min = Q(year_published__gte=int(array[0]))
max = Q(year_published__lte=int(array[1]))
if array[2] == "1":
incl_null = Q(year_published=None)
return queryset.filter((min & max) | incl_null)
else:
return queryset.filter(min & max)
想知道是否有更好的方法。
试试这个查询:
from django.db.models import Q
min_ = 0
max_ = 10
Item.objects.filter(Q(number__gte=min_, number__lte=max_) | Q(number__isnull=True))