您好我正在尝试为Django编写标记系统,但今天我在filter或Q对象(django.db.models.Q)中遇到了一个奇怪的行为。
我写了一个函数,它将搜索字符串转换为Q对象。下一步是使用这些查询过滤TaggedObject。但不幸的是,我得到了一个奇怪的行为。
当我搜索(id=20)
=>
Q: (AND: ('tags__tag__id', 20))
它返回2个具有ID 1127和132
当我搜索(id=4)
=>
Q: (AND: ('tags__tag__id', 4))
它还返回2个对象,但这次是1180和1127
这是重新设置的SQL查询:
SELECT "django_content_type"."id", "django_content_type"."name", "django_content_type"."app_label", "django_content_type"."model"
FROM "django_content_type"
WHERE ("django_content_type"."model" = slogan AND "django_content_type"."app_label" = slogans )
ORDER BY "django_content_type"."name" ASC
SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author"
FROM "slogans_slogan"
INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ("htags_objecttagbridge"."tag_id" = 4 AND "htags_objecttagbridge"."content_type_id" = 9 )
LIMIT 21
直到这里一切都很好,但当我做一些更复杂的查询,如(id=4) or (id=20)
=>
Q: (OR: ('tags__tag__id', 4), ('tags__tag__id', 20))
然后它返回4(!)对象1180,1127,1127,132
和SQL:
SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author"
FROM "slogans_slogan"
INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ((("htags_objecttagbridge"."tag_id" = 4 AND "htags_objecttagbridge"."content_type_id" = 9 ) OR "htags_objecttagbridge"."tag_id" = 20 ) AND "htags_objecttagbridge"."content_type_id" = 9 )
LIMIT 21
但ID为1127的对象会返回两次,但这不是我想要的行为。我是否必须忍受它,并将该列表统一起来,或者我可以做些不同的事情。 Q对象的表示对我来说很好。
但现在最糟糕的是,当我搜索(id=20) and (id=4)
=>
Q: (AND: ('tags__tag__id', 20), ('tags__tag__id', 4))
然后它根本不返回任何对象。但为什么?表示应该是正确的,并且具有id 1127的对象被两者标记。我错过了什么?
这里又是SQL:
SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author"
FROM "slogans_slogan"
INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ("htags_objecttagbridge"."tag_id" = 4 AND "htags_objecttagbridge"."content_type_id" = 9 AND "htags_objecttagbridge"."tag_id" = 20 )
LIMIT 21
[编辑]: 我现在意识到,这个SQL语句是错误的。至少不是我想要的,因为在这里它想要的是,一个ObjectTagBridge具有id 4并且同时具有id 20.但在我的情况下这些是2个不同的
class TaggedObject(models.Model):
"""
class that represent a tagged object
"""
tags = generic.GenericRelation('ObjectTagBridge',
blank=True, null=True)
class ObjectTagBridge(models.Model):
"""
Help to connect a generic object to a Tag.
"""
# pylint: disable-msg=W0232,R0903
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
tag = models.ForeignKey('Tag')
class Tag(models.Model):
...
感谢您的帮助
答案 0 :(得分:5)
对于问题1(唯一性):您将要进行查询distinct。复制是该类型查询的预期行为,除非您将其区分开来。
对于问题2,您可能会遇到查询集如何工作的微妙但重要的部分。如果你这样做一个查询:
mymodel.objects.filter(tags__tag__id=4, tags__tag__id=5)
您正在查询具有单标记的模型,该标记同时具有id = 4和id = 5,这当然没有标记。但如果您改为这样查询:
mymodel.objects.filter(tags__tag__id=4).filter(tags__tag__id=5)
你得到的模型在id = 4的地方有一些标签,而某些标签的id = 5。 Q对象也是如此 - 它们需要分成单独的filter
或exclude
调用,而不是指单个Tag关系。这是documented here。