Vous souhaitez donc utiliser le framework Types de contenu sur votre travail?
Commencez par vous poser cette question: "Est-ce que l'un de ces modèles doit être lié de la même manière à d'autres modèles et / ou vais-je réutiliser ces relations de manière imprévue plus tard?" La raison pour laquelle nous posons cette question est que c'est ce que le cadre des types de contenu fait le mieux: il crée des relations génériques entre les modèles. Bla bla, plongeons dans un peu de code et voyons ce que je veux dire.
# 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)
D'accord, nous avons donc un moyen de créer théoriquement cette relation. Cependant, en tant que programmeur Python, votre intellect supérieur vous dit que c'est nul et que vous pouvez faire mieux. Tape m'en cinq!
Entrez dans le cadre des types de contenu!
Eh bien, maintenant nous allons examiner de près nos modèles et les retravailler pour qu'ils soient plus «réutilisables» et intuitifs. Commençons par nous débarrasser des deux clés étrangères de notre Comment
modèle et remplaçons-les par un 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()
Alors, qu'est-ce-qu'il s'est passé? Eh bien, nous sommes entrés et avons ajouté le code nécessaire pour permettre une relation générique avec d'autres modèles. Remarquez qu'il y a plus qu'un simple GenericForeignKey
, mais aussi un ForeignKey
to ContentType
et un PositiveIntegerField
pour le object_id
. Ces champs servent à indiquer à Django le type d'objet auquel il est lié et l'id de cet objet. En réalité, cela a du sens car Django aura besoin des deux pour rechercher ces objets associés.
Eh bien, ce n'est pas très Python ... c'est un peu moche!
Vous êtes probablement à la recherche d'un code intuitif, impeccable et étanche qui ferait la fierté de Guido van Rossum . Je te comprends. Regardons le GenericRelation
terrain pour que nous puissions mettre un joli arc là-dessus.
# 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! Juste comme ça, vous pouvez travailler avec les commentaires pour ces deux modèles. En fait, allons-y et faisons cela dans notre shell (tapez à python manage.py shell
partir du répertoire de votre projet 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!"]
C'est si simple.
Quelles sont les autres implications pratiques de ces relations «génériques»?
Les clés étrangères génériques permettent des relations moins intrusives entre diverses applications. Par exemple, disons que nous avons extrait le modèle Comment dans sa propre application nommée chatterly
. Maintenant, nous voulons créer une autre application nommée noise_nimbus
où les gens stockent leur musique pour la partager avec d'autres.
Et si nous voulons ajouter des commentaires à ces chansons? Eh bien, nous pouvons simplement dessiner une relation générique:
# 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)
J'espère que vous avez trouvé cela utile, car j'aurais aimé trouver quelque chose qui m'a montré l'application plus réaliste des champs GenericForeignKey
et GenericRelation
.
Est-ce trop beau pour être vrai?
Comme pour tout dans la vie, il y a des avantages et des inconvénients. Chaque fois que vous ajoutez plus de code et plus d'abstraction, les processus sous-jacents deviennent plus lourds et un peu plus lents. L'ajout de relations génériques peut ajouter un peu d'atténuation des performances malgré le fait qu'il essaiera de mettre en cache ses résultats. Dans l'ensemble, il s'agit de savoir si la propreté et la simplicité l'emportent sur les faibles coûts de performance. Pour moi, la réponse est un million de fois oui.
Il y a plus dans le cadre des types de contenu que ce que j'ai affiché ici. Il y a tout un niveau de granularité et d'utilisation plus verbeuse, mais pour l'individu moyen, c'est ainsi que vous l'utiliserez 9 fois sur 10 à mon avis.
Relationnels génériques (?) Attention!
Une mise en garde assez importante est que lorsque vous utilisez a GenericRelation
, si le modèle qui a GenericRelation
appliqué ( Picture
) est supprimé, tous les Comment
objets related ( ) seront également supprimés. Ou du moins au moment de la rédaction de cet article.