我真的很难理解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,还有ForeignKeyContentTypePositiveIntegerField表示object_id.这些字段用于告诉Django这与什么类型的对象相关,以及该对象的id是什么.实际上,这是有道理的,因为Django需要同时查找这些相关对象.

这可不像Python那样...有点难看!

您可能正在寻找让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)

我希望你们会发现这对我有帮助,因为我会很高兴看到一些向我展示了GenericForeignKeyGenericRelation字段更现实的应用的东西.

这是不是太好了,不像是真的?

就像生活中的任何事情一样,有利也有弊.只要添加更多代码和更多抽象,底层流程就会变得更重、更慢.添加泛型关系可以稍微降低性能,尽管它会try 并智能缓存其结果.总而言之,这取决于清洁度和简单性是否超过了小的性能成本.对我来说,答案是肯定的.

除了我在这里展示的内容类型框架之外,还有更多内容类型框架.有一个完整的粒度级别和更冗长的用法,但对于普通个人来说,在我看来,这就是您将如何使用它10次中的9次.

泛型关系词(?)当心

一个相当大的caveat是,当您使用GenericRelation时,如果应用了GenericRelation(Picture)的模型被删除,所有相关的(Comment)对象也将被删除.或者至少在写这篇文章的时候是这样.

Django相关问答推荐

以特定顺序获取模型实例时出现问题

DRF中是否有有效的更新有序数据的算法?

如何在 Django 中设置与 Session 相关的字段

Django Admin:在一个部分中同时显示多个应用程序?

无法创建超级用户,因为 Django 中的一列(外键)不能为空

如何将数据库中的 None 序列化为空对象?

如何将 select_related 应用于 Django 中的 m2m 关系的对象?

Django中的多对多关系?

带有代码完成功能的 python / django 的 Sublime Text 2 和 3 设置

未捕获的类型错误:$(...).datepicker is not a function(anonymous function)

如何从 django 自定义中间件类返回 rest_framework.response 对象?

通过 django shell 保存图像/文件

Django - 如何从模型中 Select 特定列?

模型 Django 中的 ID 字段

使用 Gunicorn 运行 Django - 最佳实践

从 virtualenv 中,pip freeze > requirements.txt 给出了一堆垃圾!如何修剪它?

django python 日期时间设置为午夜

Django 应用程序运行良好,但收到 TEMPLATE_* 警告消息

访问 django 管理模板中的对象

使用 .order_by() 和 .latest() 的 Django 查询