2010-02-04 8 views
1

Fondamentalement, j'ai une classe de base appelée "Programme". J'ai alors des types de modèles de programmes plus spécifiques qui utilisent Program comme classe de base. Pour 99% de mes besoins, je ne me soucie pas de savoir si un programme est l'un des types d'enfants spécifiques. Bien sûr, il y a 1% du temps que je veux savoir si c'est un des enfants. Le problème est que si je l'ai, disons, un modèle SwimProgram et un modèle CampProgram utilisant Program comme base, il est problématique de savoir ce qu'ils sont sans un tas de blocs try/except. Ce que je veux est quelque chose comme ce qui suit:Distinguer les enfants du modèle parent avec l'héritage Django

program = models.Program.objects.get(id=15) 
if program.swimprogram: 
    ## do stuff 
elif program.campprogram: 
    ## do stuff 
else: 
    ## do other stuff 

Bien sûr, cela jette exceptions DoesNotExist. Je pourrais soit utiliser try/exceptions qui sont plus laids, ou je pourrais avoir Program un champ 'type' que les enfants mis en sauvegarde. Les deux sont faisables, mais je suis curieux de savoir si quelqu'un a de meilleures méthodes.

Répondre

4

Avez-vous essayé hasattr()? Quelque chose comme ceci:

if hasattr(program, 'swimprogram'): 
    # ... 
elif hasattr(program, 'campprogram'): 
    # ... 

Si vous n'êtes pas certain de cette approche, l'essayer dans une application de test simple en premier. Voici deux modèles simples qui devraient montrer si cela fonctionnera pour vous et la version de django que vous utilisez (testé dans django-1.1.1).

class Archive(models.Model): 
    pub_date = models.DateField() 

    def __unicode__(self): 
     return "Archive: %s" % self.pub_date 

class ArchiveB(Archive): 
    def __unicode__(self): 
     return "ArchiveB: %s" % self.pub_date 

Et puis en lui donnant un tour dans la coquille:

> a_id = Archive.objects.create(pub_date="2010-10-10").id 
> b_id = ArchiveB.objects.create(pub_date="2011-11-11").id 
> a = Archive.objects.get(id=a_id) 
> b = Archive.objects.get(id=b_id) 
> (a, b) # they both look like archive objects 
(<Archive: Archive: 2010-10-10>, <Archive: Archive: 2011-11-11>) 
> hasattr(a, 'archiveb') 
False 
> hasattr(b, 'archiveb') # but only one has access to an ArchiveB 
True 
+0

* facepalm * Merci. :) – f4nt

+0

Etes-vous sûr que cela fonctionne? Je suis sûr que 'programme' a les deux attributs. L'exception DoesNotExist se produit uniquement lorsque vous tentez d'y accéder (puisque l'héritage est modélisé avec une relation OneToOne) –

+0

yw f4nt. J'ai fait à peu près la même chose quand je me suis débrouillé pour moi-même. @piquadrat, j'ai ajouté un petit exemple pour montrer comment cela peut fonctionner. Merci pour le coup de pouce pour ajouter l'exemple. – istruble

0

// Mise à jour

Comme indiqué dans les commentaires à ce post, je suis la mauvaise question. La réponse ci-dessous ne résoudra pas le problème.


Salut f4nt,

la meilleure façon que je peux penser droit est maintenant la suivante:

program = models.Program.objects.get(id=15) 

if program.__class__.__name__ == 'ModelA': 
    # to something 

if program.__class__.__name__ == 'ModelB': 
    # to something 

pour en faire un peu mieux que vous pourriez écrire une méthode dans le modèle de base :

class MyModel(models.Model): 

    def instanceOfModel(self, model_name): 
    return self.__class__.__name__ == model_name 

de cette façon, le code de dessus serait ressembler à ceci:

program = models.Program.objects.get(id=15) 

if program.instanceOfModel('ModelA'): 
    # to something 

if program.instanceOfModel('ModelB'): 
    # to something 

Mais comme vous pouvez l'imaginer c'est moche. Vous pouvez regarder dans le cadre content type qui pourrait vous aider à faire la même chose sauf plus élégant.

Espérons que ça aide!

+1

Je ne pense pas que cela fonctionnera.Django docu dit clairement: * LES QUERYSETS RETOURNENT TOUJOURS LE MODÈLE DEMANDÉ *. Donc, si vous demandez des objets Program, alors 'program .__ class __.__ name__' sera' Program'. –

+0

Merci d'avoir signalé cela à Felix. Mais je l'ai essayé dans le shell django et ça a marché. – Jens

+0

Oui, juste fait un test rapide, et il retournera "Program". – f4nt

1

Il y a quelques semaines, quelqu'un sur les développeurs django-liste de diffusion a introduit une extension très intéressante à ORM de Django qui fait retour de QuerySets objets sous-classés à la place des objets de la classe parente. Vous pouvez lire tout ici:

http://bserve.webhop.org/wiki/django_polymorphic

Je ne l'ai pas essayé moi-même encore (mais certainement), mais il semble s'adapter à votre cas d'utilisation.

+0

Le lien est mort, je pense que le projet correspondant est https://github.com/bconstantin/django_polymorphic mais on dirait qu'il n'a jamais bougé depuis sa validation initiale ... – Stefano

Questions connexes