Получить весь объект с пустым набором связанных - PullRequest
1 голос
/ 21 декабря 2010

У меня есть две модели:

class Content(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(db_index=True)
    content_object = generic.GenericForeignKey()
    show = models.BooleanField(default=False)

class Foo(models.Model):
    rel = generic.GenericRelation(Content)

И я хочу получить все методы Foo, которые имеют связанный объект содержимого (их будет только один) с show==True или которые вообще не имеют связанных объектов. Что-то вроде:

Foo.objects.filter(Q(rel__show=True) | Q(rel__hasnone=True))

Но, конечно, в django нет ничего похожего на hasnone.

Есть ли другой способ, которым я могу это сделать (к сожалению, агрегация не работает с общими отношениями, и я не могу считать элементы).

1 Ответ

1 голос
/ 23 декабря 2010

Хорошо, я думаю, что у меня есть ответ, который может удовлетворить некоторых из нас (к сожалению, не меня).

Что мне нужно, так это LEFT OUTER JOIN, который Django не поддерживает (все объединения, объявленные пользователем, являются INNERиз них), что-то вроде:

SELECT *, `foobar_bar`.`show` AS `show` FROM `foobar_foo` LEFT OUTER JOIN `foobar_bar` 
    ON (`foobar_foo`.`id` = `foobar_bar`.`object_id` and 
        ctype = `foobar_bar`.`content_type_id`) 
    WHERE show=TRUE OR show=NULL

Я предположил, что обе модели находятся в foobar приложении, а ctype - это content_type модели Foo.Я не нашел способ сделать такой запрос, но мы можем сделать что-то вроде:

SELECT *, `foobar_bar`.`show` AS `show` FROM `foobar_foo` LEFT OUTER JOIN `foobar_bar` 
    ON (`foobar_foo`.`id` = `foobar_bar`.`object_id`
    WHERE (show=TRUE OR show=NULL) AND ctype = `foobar_bar`.`content_type_id`

Это не является удовлетворительным исключением (может объединять кортежи с другим типом ctype только на основе идентификатора объекта), но все еще полезно.Способ сделать такой запрос я нашел по тексту ссылки .Это будет что-то вроде:

qs = Foo.objects.all()

qs.query.join((None, 'foobar_foo', None, None))
qs.query.join(('foobar_foo', 'foobar_bar', 'id', 'object_id'), promote=True)
foos.
qs = qs.extra(select = {'show': 'foobar_bar.show',},
              where = "(show=TRUE OR show=NULL) AND ctype = `foobar_bar`.`content_type_id`")

Обычно использование query.join((,), promote=True) дает нам LEFT QUERY JOIN вместо INNER, но мы можем передать только один аргумент ON, что слишком мало, чтобы полностью решить эту проблему, но все жеполезно.

...