2009-02-26 4 views
2

J'ai ces deux modèles simples, A et B:Comment puis-je interroger un modèle par s'il existe une instance de sous-classe?

from django.db import models 

class A(models.Model): 
    name = models.CharField(max_length=10) 

class B(A): 
    age = models.IntegerField() 

Maintenant, comment puis-je interroger pour toutes les instances de A qui ne disposent pas d'une instance de B? La seule façon que j'ai trouvé nécessite un champ explicitement unique sur chaque sous-classe, qui n'est pas NULL, de sorte que je puisse faire A.objects.filter (b__this_is_a_b = None), par exemple, pour obtenir des instances qui ne sont pas aussi B instances. Je cherche un moyen de le faire sans ajouter un drapeau idiot explicite comme ça.

Je ne souhaite pas non plus interroger tous les objets, puis les filtrer en Python. Je veux que la DB le fasse pour moi, ce qui est quelque chose comme SELECT * FROM A WHERE A.id in (SELECT id from B)

+0

OÙ A.id * pas * dans (SELECT ...), je pense? – AdamKG

Répondre

0

Je ne travaille pas avec django, mais on dirait que vous voulez la méthode python intégrée isinstance (obj, type).

Edit:
Would A.objects.exclude (id__exact = B__id) travail?

+0

Malheureusement, non. J'essaye de donner à l'ORM de django les bonnes instructions pour générer le SQL pour faire cela pour moi, plutôt que de les filtrer du côté client. – ironfroggy

1

Je ne suis pas sûr qu'il soit possible de le faire purement dans la BD avec l'ORM de Django, en une seule requête. Voici le meilleur que je suis en mesure de le faire:

A.objects.exclude(id__in=[r[0] for r in B.objects.values_list("a_ptr_id")]) 

C'est 2 requêtes DB, et fonctionne mieux avec un héritage simpliste graphique - chaque sous-classe de A nécessiterait une nouvelle requête de base de données.


Bon, il a fallu beaucoup d'essais et d'erreurs, mais j'ai une solution. Il est laid comme tout l'enfer, et le SQL est probablement pire que de simplement aller avec deux requêtes, mais vous pouvez faire quelque chose comme ceci:

A.objects.exclude(b__age__isnull=True).exclude(b__age_isnull=False) 

Il n'y a pas moyen d'obtenir Django pour faire la jointure sans faire référence à un champ sur b. Mais avec ces .exclude() s successifs, vous faites tout A avec une sous-classe B correspond l'un ou l'autre des exclus. Il ne vous reste plus que de A sans sous-classe B.

Quoi qu'il en soit, c'est un cas d'utilisation intéressante, vous devriez la mettre sur django-dev ...

+0

J'accepterais cette réponse, mais il ne semble pas que toute réponse soit vraiment "correcte" dans un bon sens. Je vais l'aborder avec django-dev comme vous le suggérez. – ironfroggy

2

Depuis une version de django ou python, cela fonctionne ainsi:

A.Objects.all().filter(b__isnull=True) 

parce que si a est un objet ab donne la sous-classe B de quand il existe

Je sais que c'est une vieille question, mais ma réponse pourrait aider les nouveaux chercheurs sur ce sujet.

voir aussi:

multi table inheritance

Et un de mes propres questions à ce sujet: downcasting a super class to a sub class

Questions connexes