2010-12-20 3 views
1

J'ai deux modèles:Obtenez tous les objets avec ensemble vide de ceux liés

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) 

Et je veux toutes les méthodes Foo qui est l'objet du contenu lié (il n'y aurait qu'un seul) a show==True ou qui doesn pas d'objet apparenté du tout. Quelque chose comme:

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

Mais bien sûr, il n'y a rien comme hasnone dans django.

Existe-t-il un autre moyen de réaliser cela (malheureusement, l'agrégation ne fonctionne pas avec les relations génériques et je ne peux pas compter les éléments).

+0

J'ai vu votre réponse ci-dessous, mais voici une idée plus simple: faites défiler les ensembles associés et ajoutez tous les objets associés à une liste. Parcourez à nouveau le modèle et ignorez tous les enregistrements de la liste. Cela serait plus lent, mais aurait l'avantage de coller entièrement avec python et l'ORM de Django. –

Répondre

1

Ok, je pense que j'ai une réponse qui pourrait satisfaire certains d'entre nous (malheureusement pas moi).

Ce que je dois était LEFT OUTER JOIN qui Django ne supporte pas (tous les joints déclarés par l'utilisateur sont les INNER), quelque chose comme:

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 

Je suppose que les deux modèles sont en foobar application et ctype est content_type du modèle Foo. Je ne l'ai pas trouvé moyen de faire une telle requête, mais nous pouvons faire quelque chose comme:

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` 

Il est exclusif pas satisfaisant (pourrait rejoindre tuples avec différents ctype juste basant sur l'identifiant de l'objet), mais est toujours utile. Façon de faire une telle requête, j'ai trouvé au link text. Ce sera quelque chose comme:

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`") 

En général, en utilisant query.join((,), promote=True) nous obtient GAUCHE QUERY REJOIGNEZ au lieu de INNER, mais nous pouvons passer seul sur argument, qui est trop peu pour résoudre complètement ce problème mais toujours utile.

Questions connexes