2009-09-08 12 views
2

Étant donné les modèles suivants: (ne me dérange pas les TextFields il sont juste pour illustration)Django héritage modèle, les modèles de filtrage

class Base(models.Model): 
    field1 = models.TextField() 

    class Meta: 
     abstract=True 

class Child1(Base): 
    child1_field = models.TextField() 

class Child2(Base): 
    child2_field = models.TextField() 


class Content(models.Model): 
    aso_items = models.ManyToManyField('Base') 

Selon ces définitions un objet contenu peut être associé à plus d'une base objet, par exemple. une interview (= Objet de contenu) peut être liée à un musicien (= objet Child1), un filmdirector (= Child2), etc.

Maintenant, pour ma question: Est-il possible de filtrer les objets Contenu selon quel modèle? le champ aso_items pointe vers? Un exemple: Supposons que je souhaite un Queryset contenant tous les objets Content associés à un objet spécifique de Child1 (par exemple toutes les interviews associées au musicien Bob Dylan), comment puis-je y parvenir? En outre, que se passe-t-il si je veux un QuerySet contenant tous les objets Content associés aux objets Child1 (par exemple toutes les interviews associées aux musiciens) Comment cela change-t-il le filtrage?

Merci à l'avance ps: je rencontre quelques problèmes avec l'espace blanc dans l'aperçu, pardonnez-moi

Répondre

7

Vous devriez vérifier la section des documents Django concernant l'utilisation de related_name pour les classes de base abstraites. http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name

Pour citer les docs:

If you are using the related_name attribute on a ForeignKey or ManyToManyField, you must always specify a unique reverse name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including related_name) each time.

To work around this problem, when you are using related_name in an abstract base class (only), part of the name should be the string %(class)s . This is replaced by the lower-cased name of the child class that the field is used in. Since each class has a different name, each related name will end up being different.

En utilisant cette information, je recommande de transférer le champ m2m dans la classe de base:

class Content(models.Model): 
    # Add remaining fields for Content 
    pass 

class Base(models.Model): 
    field1 = models.TextField() 
    items = models.ManyToManyField(Content,related_name="%(class)s_related") 

    class Meta: 
     abstract=True 

class Child1(Base): 
    child1_field = models.TextField() 

class Child2(Base): 
    child2_field = models.TextField() 
+0

C'est une bonne solution si le modèle de contenu n'est pas abstrait aussi. Si le modèle de contenu était aussi un modèle abstrait, alors il ne fonctionnerait plus (mais c'est un problème différent de ce que j'ai posté) – logion

+0

Assez juste. Dans le cas où les deux sont abstraits, je pense que vous devrez utiliser le framework ContentType comme suggéré par Adam. –

2

Apparemment, une relation ForeignKey (ou ManyToMany pour cette matière) avec une classe abstraite n'est pas autorisé. Je reçois l'erreur suivante: 'AssertionError: ForeignKey ne peut pas définir de relation avec la classe abstraite Artiest'.

Une solution possible est de définir la classe de base comme non abstraite, mais cela implique que l'on pourrait instancier des modèles de la classe de base. Ce qui n'est pas le comportement que je veux (après tout c'était une classe abstraite) Est-ce que quelqu'un a rencontré le même problème comment l'avez-vous résolu? Des alternatives?

1

Jetez un oeil à http://www.djangoproject.com/documentation/models/generic_relations/ qui passe par des relations génériques. Votre modèle de contenu correspond à leur modèle TaggedItem, et votre modèle de base correspond à leur modèle Animal/Légume/Minéral (avec extension de Child1 et Child2).

Obtenir tous les objets de contenu pour un seul enfant serait (en supposant que vous définissez la GenericRelation à contenu à l'intérieur de base):

child_contents = childObject.contents.all() 

Et pour tous les objets de contenu pour un modèle:

ctype = ContentType.objects.get_for_model(Child1) 
all_child_contents = Content.objects.filter(content_type=ctype) 
+0

Cela pourrait être ce que je suis à la recherche, le ContentType Le cadre qui permet l'utilisation de relations génériques est documenté à http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/. L'application de commentaires standard dans django (django.contrib.comments) utilise ce framework, fournissant ainsi un exemple de code utilisable. Je regarde maintenant. – logion

+0

Je suis préoccupé par les performances, notre site reçoit environ 11k hits par jour et je voudrais que ma solution soit évolutive sur le terrain (le hitcount pourrait augmenter par exemple) Quelqu'un peut-il faire la lumière sur ce sujet? Le serveur de production s'exécutera sur un VPS de slicehost. – logion

Questions connexes