假设一个模型
class Foo(models.Model):
bar = models.CommaSeparatedIntegerField('Filter Me!')
bar
的内容可能如下,例如12,35,67,142
。
我想查询Foo
中有42
的所有bar
:
all_42_foos = Foo.objects.filter(bar__contains="42")
没有给出正确的结果,因为CommaSeparatedIntegerField
继承自CharField
,过滤器评估使用字段的字符串内容(上面的例子也与142
匹配)
在检查.split(",")
之前,如何在bar
字段上执行42
过滤器?我真的不希望bar
成为ManyToMany
,因为它是一个可怕的开销。
答案 0 :(得分:13)
如下:
from django.db.models import Q
all_42_foos = Foo.objects.filter( Q(bar__startswith='42,') | Q(bar__endswith=',42') | Q(bar__contains=',42,') | Q(bar__exact='42') )
虽然这是一个冗长的查询,但我认为沿着这些方向的某些东西将是获得你所寻找的东西的唯一途径。可能值得把它变成一个单独的函数
def all_x_foos(x):
return Foo.objects.filter( Q(bar__startswith=x+',') | Q(bar__endswith=','+x) | Q(bar__contains=',{0},'.format(x)) | Q(bar__exact=x) )
出于好奇,您是否已经使用多对多方式和您描述的伪多对多方法检查了应用的实际性能?
答案 1 :(得分:0)
这个答案是@desfido的答案的扩展。基本上将对象类型与过滤CommaSeperatedInteger字段的函数解耦。转出此解决方案比使用正则表达式找到正确的值更快。我使用了这个正则表达式。< / p>
_regex = r"(^|(\d*,)+)(%s)((,\d*)+|$)" %('|'.join(_ids))
如果要在逗号分隔值中搜索多个值,可以在循环中调用下面给出的函数
此功能的关键字参数为: -
cs_field_name将是逗号分隔整数字段的名称。
x将是要搜索的整数。
它返回一个Q对象,然后可以将其组合并用于过滤
def search_comma_seperated_field(cs_field_name,x):
startswith_key = cs_field_name + "__startswith"
endswith_key = cs_field_name + "__endswith"
contains_key = cs_field_name + "__contains"
exact_key = cs_field_name + "__exact"
return Q(**{startswith_key : x+','}) | \
Q(**{endswith_key:','+x}) |\
Q(**{contains_key : ',{0},'.format(x)}) |\
Q(**{exact_key:x})
答案 2 :(得分:0)
您也可以用一个正则表达式编写它:
all_42_foos = Foo.objects.filter(bar__regex=u'^42,|,42,|,42$|^42$')
或
bar_number = 42
bar_regex = r'^{0},|,{0},|,{0}$|^{0}$'.format(bar_number)
all_42_foos = Foo.objects.filter(bar__regex=bar_regex)