Привет! Я пытаюсь написать систему тегов для Django, но сегодня я столкнулся со странным поведением в фильтре или объекте Q (django.db.models.Q).
Я написал функцию, которая преобразует строку поиска в объект Q. Следующим шагом будет фильтрация TaggedObject по этим запросам. Но, к сожалению, у меня странное поведение.
поиск только одного элемента тега:
когда я ищу (id=20)
=>
Q: (AND: ('tags__tag__id', 20))
и возвращает 2 объекта Taged с идентификаторами 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
Но объект с идентификатором 1127 возвращается дважды, но это не то поведение, которое мне нужно. Должен ли я жить с этим и унифицировать этот список, или я могу сделать что-то другое? Представление объекта Q выглядит хорошо для меня.
поиск по двум тегам и соединению
Но самое страшное сейчас, когда я ищу (id=20) and (id=4)
=>
Q: (AND: ('tags__tag__id', 20), ('tags__tag__id', 4))
тогда он вообще не возвращает никаких объектов. Но почему? Представление должно быть в порядке, и объект с идентификатором 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 имел идентификатор 4 и одновременно идентификатор 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):
...
Спасибо за вашу помощь