Quindi vuoi usare il framework Tipi di contenuto per il tuo lavoro?
Inizia ponendoti questa domanda: "Qualcuno di questi modelli deve essere correlato allo stesso modo con altri modelli e / o riutilizzerò queste relazioni in modi non previsti più avanti?" Il motivo per cui facciamo questa domanda è perché questo è ciò che fa meglio il framework Tipi di contenuto: crea relazioni generiche tra i modelli. Blah blah, immergiamoci in un po 'di codice e vediamo cosa intendo.
# ourapp.models
from django.conf import settings
from django.db import models
# Assign the User model in case it has been "swapped"
User = settings.AUTH_USER_MODEL
# Create your models here
class Post(models.Model):
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
body = models.TextField(blank=True)
class Picture(models.Model):
author = models.ForeignKey(User)
image = models.ImageField()
caption = models.TextField(blank=True)
class Comment(models.Model):
author = models.ForeignKey(User)
body = models.TextField(blank=True)
post = models.ForeignKey(Post)
picture = models.ForeignKey(Picture)
Va bene, quindi abbiamo un modo per creare teoricamente questa relazione. Tuttavia, come programmatore Python, il tuo intelletto superiore ti sta dicendo che fa schifo e puoi fare di meglio. Il cinque!
Entra nel framework Tipi di contenuto!
Bene, ora daremo uno sguardo da vicino ai nostri modelli e li rielaboreremo per renderli più "riutilizzabili" e intuitivi. Iniziamo eliminando le due chiavi esterne sul nostro Commentmodello e sostituendole con una GenericForeignKey.
# ourapp.models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
...
class Comment(models.Model):
author = models.ForeignKey(User)
body = models.TextField(blank=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
Allora, cos'è successo? Bene, siamo entrati e abbiamo aggiunto il codice necessario per consentire una relazione generica con altri modelli. Notare come non ci sia solo un GenericForeignKey, ma anche un ForeignKeya ContentTypee un PositiveIntegerFieldper il object_id. Questi campi servono per dire a Django a quale tipo di oggetto è correlato e qual è l'id per quell'oggetto. In realtà, questo ha senso perché Django avrà bisogno di entrambi per cercare questi oggetti correlati.
Beh, non è molto simile a Python ... è un po 'brutto!
Probabilmente stai cercando un codice a tenuta stagna, perfettamente pulito e intuitivo che renderebbe orgoglioso Guido van Rossum . Ti capisco. Diamo un'occhiata al GenericRelationcampo in modo da poter fare un bel inchino su questo.
# ourapp.models
from django.contrib.contenttypes.fields import GenericRelation
...
class Post(models.Model):
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
body = models.TextField(blank=True)
comments = GenericRelation('Comment')
class Picture(models.Model):
author = models.ForeignKey(User)
image = models.ImageField()
caption = models.TextField(blank=True)
comments = GenericRelation('Comment')
Bam! Proprio così puoi lavorare con i commenti per questi due modelli. In effetti, andiamo avanti e facciamolo nella nostra shell (digitare python manage.py shelldalla directory del progetto Django).
>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture, Post
# We use get_user_model() since we are referencing directly
User = get_user_model()
# Grab our own User object
>>> me = User.objects.get(username='myusername')
# Grab the first of our own pictures so we can comment on it
>>> pic = Picture.objects.get(author=me)
# Let's start making a comment for our own picture
>>> pic.comments.create(author=me, body="Man, I'm cool!")
# Let's go ahead and retrieve the comments for this picture now
>>> pic.comments.all()
[<Comment: "Man, I'm cool!">]
# Same for Post comments
>>> post = Post.objects.get(author=me)
>>> post.comments.create(author=me, body="So easy to comment now!")
>>> post.comments.all()
[<Comment: "So easy to comment now!"]
È così semplice.
Quali sono le altre implicazioni pratiche di queste relazioni "generiche"?
Le chiavi esterne generiche consentono relazioni meno invasive tra le varie applicazioni. Ad esempio, supponiamo di aver estratto il modello Comment nella sua app denominata chatterly. Ora vogliamo creare un'altra applicazione chiamata noise_nimbusdove le persone memorizzano la loro musica per condividerla con gli altri.
E se volessimo aggiungere commenti a quelle canzoni? Bene, possiamo solo disegnare una relazione generica:
# noise_nimbus.models
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from chatterly.models import Comment
# For a third time, we take the time to ensure custom Auth isn't overlooked
User = settings.AUTH_USER_MODEL
# Create your models here
class Song(models.Model):
'''
A song which can be commented on.
'''
file = models.FileField()
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
comments = GenericRelation(Comment)
Spero che voi ragazzi vi sia stato utile perché mi sarebbe piaciuto trovare qualcosa che mi mostrasse l'applicazione GenericForeignKeye i GenericRelationcampi più realistici .
È troppo bello per essere vero?
Come per qualsiasi cosa nella vita, ci sono pro e contro. Ogni volta che aggiungi più codice e più astrazione, i processi sottostanti diventano più pesanti e un po 'più lenti. L'aggiunta di relazioni generiche può aggiungere un po 'di smorzamento delle prestazioni nonostante il fatto che proverà a mettere in cache i risultati. Tutto sommato, dipende dal fatto che la pulizia e la semplicità superino i piccoli costi delle prestazioni. Per me, la risposta è un milione di volte sì.
C'è molto di più nel framework Tipi di contenuto di quello che ho visualizzato qui. C'è un intero livello di granularità e un uso più dettagliato, ma per l'individuo medio, questo è come lo userete 9 su 10 volte secondo me.
Rapporti generici (?) Attenzione!
Un avvertimento piuttosto grande è che quando si utilizza a GenericRelation, se il modello che ha il GenericRelationmetodo apply ( Picture) viene eliminato, Commentverranno eliminati anche tutti gli oggetti correlati ( ). O almeno al momento della stesura di questo scritto.