我正在尝试在Django中构造一个查询集,其中一个字段的值不包含在同一个表的任何实例中。举个例子,采用这个模型:
class MyModel(models.Model):
text = models.CharField(max_length = 100)
我可以使用以下循环获得非重复的查询集:
from django.db.models import Q
not_contained = MyModel.objects.all()
for instance in MyModel.objects.all():
not_contained=not_contained.exclude(Q(text__contains=instance.text) & ~Q(id=instance.id))
我的问题是,是否有更直接地这样做的方法,并避免在这里显式循环?
答案 0 :(得分:1)
我认为你可以在这里使用extra()。
例如:
>>> MyModel.objects.all()
[<MyModel: unique>, <MyModel: onemore>, <MyModel: foo>, <MyModel: bar>, <MyModel: bar123>]
>>> MyModel.objects.extra(select={'cnt': 'SELECT COUNT (*) FROM myapp_mymodel B WHERE B.text LIKE "%%" || myapp_mymodel.text || "%%"'}, where=['cnt = 1'])
[<MyModel: unique>, <MyModel: onemore>, <MyModel: foo>, <MyModel: bar123>]
如您所见,第二个查询集不包含“bar”。额外的缺点是它是特定于DBMS的。示例适用于sqlite(对于mysql,您可能需要使用CONCAT等替换||)。
如果你有理解代码的麻烦,sql查询可以帮助:
>>> print MyModel.objects.extra(select={'cnt': 'SELECT COUNT (*) FROM myapp_mymodel B WHERE B.text LIKE "%%" || myapp_mymodel.text || "%%"'}, where=['cnt = 1']).query
SELECT (SELECT COUNT (*) FROM myapp_mymodel B WHERE B.text LIKE "%" || myapp_mymodel.text || "%") AS "cnt", "myapp_mymodel"."id", "myapp_mymodel"."text" FROM "myapp_mymodel" WHERE (cnt = 1)