20

Ich habe die Django-Dokumente bezüglich des contenttypes-Frameworks mehrere Male untersucht und ich verstehe es einfach nicht gut genug, um generische Beziehungen in meinem Projekt zu implementieren. Ich habe nach Online-Beispielen oder Tutorials zu diesem Thema gesucht, aber ich kann kein einziges finden. Nennen Sie mich dumm, aber ich brauche Hilfe bei dieser Frage (bitte antworten Sie nicht einfach mit den Dokumenten). Aufgrund des Mangels an Ressourcen online, glaube ich, wenn du diese Frage mit einem gründlichen Beispiel beantwortest, ist deine Antwort vielleicht das hilfreichste Beispiel, das bis dato online bezüglich der generischen Django-Beziehungen verfügbar ist (Bonus!).Django: Beispiel für generische Beziehungen mit dem contenttypes-Framework?

Meine Frage ist also: Kann jemand ein einfaches Beispiel der Modelle zeigen und vielleicht ein paar Zeilen Code, die zeigen, wie man mit Instanzen eines generischen Modells interagiert?


Als Inspiration, hier ist das, was ich würde glauben, eine sehr häufige Situation:

Eine Website hat Medienelemente, die die gleichen weitgehend behandelt werden, sind aber etwas anders. Nehmen wir zum Beispiel an, dass es Bild- und Videoelemente gibt und Benutzer ein Element oder einen Kommentar zu einem Objekt "mögen" können. Die Likes und Kommentare sollten gleich behandelt werden, unabhängig davon, ob sie auf einem Bild oder einem Videoelement gepostet werden. Wenn ein ItemView zum Anzeigen eines Bildes oder eines Videos im Album eines Benutzers vorhanden ist, sind die folgenden Arten von Anrufen möglich: mediaitem.comments.all() oder len(mediaitem.likes.all()) oder comment.user_who_commented, ohne zu wissen, um welche Art von Medienelement es sich handelt (Bild oder Video) .

Ich glaube, Sie sechs Modelle dafür brauchen würden:

  • Abstrakt MediaItem Klasse
  • Zwei verschiedene Arten von Artikeln Medien: ImageItem und VideoItem
  • Abstrakt MediaItemActions Klasse
  • Zwei verschiedene Arten von Aktionen, die in Bezug auf Medienelemente ausgeführt werden können: Like und Comment

Wenn Sie wissen, wie diese Django Funktion nutzen zu können, bitte zeigen Sie uns ein vollständiges Beispiel! Ich habe das Gefühl, dass es ein extrem leistungsfähiges Werkzeug sein würde und es schmerzt, es in meiner Anwendung zu verwenden. Je expliziter, desto besser.

Antwort

5

Ihr Anwendungsfall klingt sehr ähnlich dem (jetzt veralteten) Django comments framework. Wenn Sie die models auschecken, werden Sie sehen, wie Sie eine generische Beziehung in BaseCommentAbstractModel verwenden - beachten Sie, dass Sie alle drei Felder benötigen, ein ForeignKey zu ContentType, ein Feld, um die Objekte pk s und das GenericForeignKey Feld zu halten.

Wie für die Abfrage von Objekten von GenericForeignKey, können Sie einige Beispiele in der template tags in diesem Projekt sehen. Siehe beispielsweise die get_query_set-Methode in BaseCommentNode, die Kommentare durch Abfragen des Inhaltstyps und des pk des Zielobjekts abruft.

def get_query_set(self, context): 
    ctype, object_pk = self.get_target_ctype_pk(context) 
    if not object_pk: 
     return self.comment_model.objects.none() 

    qs = self.comment_model.objects.filter(
     content_type = ctype, 
     object_pk = smart_text(object_pk), 
     site__pk  = settings.SITE_ID, 
    ) 
1

Eine andere Option ist Polymorphic Models. Ich werde nicht sagen, dass es so ist, wie Sie gehen sollten, aber dass es vielleicht eine Option sein könnte.

Ich bin ein Fan von beiden generischen Fremdschlüssel und polymorphe Modelle. Polymorphe Modelle funktionieren am besten in solchen Szenarien, in denen die Modelle sehr ähnlich sind.

3

Ich habe tatsächlich eine sehr ähnliche Situation in einem meiner Projekte mit verschiedenen Medientypen.

class TaggedItem(models.Model): 
    tag = models.SlugField() 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

class ReviewedItem(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 
    review = models.ForeignKey("Review") 

class CreativeWork(models.Model): 
    #other fields 
    keywords = generic.GenericRelation("TaggedItem",null=True, blank=True, default=None) 
    reviews = generic.GenericRelation("ReviewedItem",null=True, blank=True, default=None) 

class MediaObject(CreativeWork): 
    #fields 
class VideoObject(MediaObject): 
    #fields 
class AudioObject(MediaObject): 
    #fields 

Jedes Video oder Audio ist ein MediaObject, das eine CreativeWork ist. CreativeWorks hat eine GenericRelation für Tags und Reviews. So kann jetzt alles markiert oder überprüft werden.

Alles, was Sie brauchen, ist, dass die 'Aktion' einen ForeignKey zu ContentType hat. Dann fügen Sie Ihrem Modell eine GenericRelation hinzu. Ich fand die django.docs wirklich sehr hilfreich :) Aber wenn nicht hoffe das hilft.