我真的很难理解Django内容类型的概念.它让人感觉非常黑客,最终与Python的工作方式背道而驰.也就是说,如果我要使用Django,那么我必须在框架的范围内工作.
所以我来这里想知道有没有人能给出一个实际的例子,说明内容类型是如何工作的,以及你将如何实现它.我 comments 过的几乎所有的教程(主要在博客上)都没有很好地涵盖这个概念.他们似乎从Django文档中断的地方重新开始(似乎无处可寻).
我真的很难理解Django内容类型的概念.它让人感觉非常黑客,最终与Python的工作方式背道而驰.也就是说,如果我要使用Django,那么我必须在框架的范围内工作.
所以我来这里想知道有没有人能给出一个实际的例子,说明内容类型是如何工作的,以及你将如何实现它.我 comments 过的几乎所有的教程(主要在博客上)都没有很好地涵盖这个概念.他们似乎从Django文档中断的地方重新开始(似乎无处可寻).
从问自己这个问题开始:"这些模型中是否有任何一个需要以同样的方式与其他模型相关,和/或我以后会以不可预见的方式重用这些关系吗?"我们问这个问题的原因是因为这是内容类型框架最擅长的:它创建模型之间的一般关系.等等,让我们深入研究一些代码,看看我的意思.
# 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)
好的,所以理论上我们确实有办法建立这种关系.然而,作为一名Python程序员,您卓越的智力告诉您这很糟糕,您可以做得更好.击掌!
好了,现在我们将仔细研究一下我们的模型,并对它们进行修改,使其更"可重用"和更直观.让我们首先go 掉Comment
型号上的两个外键,代之以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()
那么,发生了什么?我们加入了必要的代码,允许与其他模型建立通用关系.请注意,这里不仅有GenericForeignKey
,还有ForeignKey
到ContentType
和PositiveIntegerField
表示object_id
.这些字段用于告诉Django这与什么类型的对象相关,以及该对象的id是什么.实际上,这是有道理的,因为Django需要同时查找这些相关对象.
您可能正在寻找让Guido van Rossum人感到自豪的密不透风、一尘不染、直观的代码.我明白你的意思.让我们看一下GenericRelation
字段,这样我们就可以在上面画一个漂亮的蝴蝶结.
# 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')
砰!就像这样,您可以使用这两个模型的注释.事实上,让我们继续在shell中这样做(从Django项目目录中键入python manage.py shell
).
>>> 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!"]
就这么简单.
通用外键允许在各种应用程序之间建立较少干扰的关系.例如,假设我们把 comments 模型拉到它自己的名为chatterly
的应用程序中.现在我们想创建另一个名为noise_nimbus
的应用程序,人们可以在其中存储自己的音乐与他人共享.
如果我们想给这些歌曲添加 comments 怎么办?嗯,我们可以画一个一般的关系:
# 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)
我希望你们会发现这对我有帮助,因为我会很高兴看到一些向我展示了GenericForeignKey
和GenericRelation
字段更现实的应用的东西.
就像生活中的任何事情一样,有利也有弊.只要添加更多代码和更多抽象,底层流程就会变得更重、更慢.添加泛型关系可以稍微降低性能,尽管它会try 并智能缓存其结果.总而言之,这取决于清洁度和简单性是否超过了小的性能成本.对我来说,答案是肯定的.
除了我在这里展示的内容类型框架之外,还有更多内容类型框架.有一个完整的粒度级别和更冗长的用法,但对于普通个人来说,在我看来,这就是您将如何使用它10次中的9次.
一个相当大的caveat是,当您使用GenericRelation
时,如果应用了GenericRelation
(Picture
)的模型被删除,所有相关的(Comment
)对象也将被删除.或者至少在写这篇文章的时候是这样.