Python Django 内容类型究竟是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20895429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:28:54  来源:igfitidea点击:

How exactly do Django content types work?

pythondjango

提问by Chris Shelton

I'm really having a difficult time grasping the concept of Django's content types. It feels very hackish and, ultimately, against how Python tends to do things. That being said, if I'm going to use Django then I have to work within the confines of the framework.

我真的很难掌握 Django 内容类型的概念。感觉非常hackish,最终与Python 做事的方式背道而驰。话虽如此,如果我要使用 Django,那么我必须在框架的范围内工作。

So I'm coming here wondering if anyone can give a practical real world example of how a content type works and how you would implement it. Almost all the tutorials (mostly on blogs) I have reviewed don't do a great job really covering the concept. They seem to pick up where the Django documentation left off (what seems like nowhere).

所以我来到这里想知道是否有人可以给出一个实际的现实世界示例,说明内容类型如何工作以及如何实现它。我看过的几乎所有教程(主要在博客上)都没有很好地真正涵盖这个概念。他们似乎从 Django 文档停止的地方开始(似乎无处可去)。

采纳答案by Chris Shelton

So you want to use the Content Types framework on your work?

那么您想在您的工作中使用内容类型框架吗?

Start by asking yourself this question: "Do any of these models need to be related in the same way to other models and/or will I be reusing these relationships in unforseen ways later down the road?" The reason why we ask this question is because this is what the Content Types framework does best: it creates generic relations between models. Blah blah, let's dive into some code and see what I mean.

首先问自己这个问题:“这些模型中的任何一个是否需要以相同的方式与其他模型相关联和/或我是否会在以后以不可预见的方式重用这些关系?” 我们问这个问题的原因是因为这是内容类型框架最擅长的:它在模型之间创建通用关系。废话废话,让我们深入研究一些代码,看看我的意思。

# 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)

Okay, so we do have a way to theoretically create this relationship. However, as a Python programmer, your superior intellect is telling you this sucks and you can do better. High five!

好的,所以我们确实有办法在理论上建立这种关系。然而,作为一名 Python 程序员,你卓越的智力告诉你这很糟糕,你可以做得更好。击掌!

Enter the Content Types framework!

进入内容类型框架!

Well, now we're going to take a close look at our models and rework them to be more "reusable" and intuitive. Let's start by getting rid of the two foreign keys on our Commentmodel and replace them with a GenericForeignKey.

好吧,现在我们将仔细研究我们的模型并重新设计它们以使其更“可重用”和更直观。让我们首先摆脱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()

So, what happened? Well, we went in and added the necessary code to allow for a generic relation to other models. Notice how there is more than just a GenericForeignKey, but also a ForeignKeyto ContentTypeand a PositiveIntegerFieldfor the object_id. These fields are for telling Django what type of object this is related to and what the id is for that object. In reality, this makes sense because Django will need both to lookup these related objects.

所以发生了什么事?好吧,我们进入并添加了必要的代码以允许与其他模型的通用关系。请注意,除了 a 之外GenericForeignKey,还有一个 ForeignKeytoContentType和一个PositiveIntegerFieldfor object_id。这些字段用于告诉 Django 这与什么类型的对象相关以及该对象的 id 是什么。实际上,这是有道理的,因为 Django 需要两者来查找这些相关对象。

Well, that's not very Python-like... its kinda ugly!

嗯,这不是很像 Python ……它有点丑!

You are probably looking for air-tight, spotless, intuitive code that would make Guido van Rossumproud. I get you. Let's look at the GenericRelationfield so we can put a pretty bow on this.

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

Bam! Just like that you can work with the Comments for these two models. In fact, let's go ahead and do that in our shell (type python manage.py shellfrom your Django project directory).

砰!就像这样,您可以使用这两个模型的注释。事实上,让我们继续在我们的 shell 中执行此操作(python manage.py shell从您的 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!"]

It's that simple.

就这么简单。

What are the other practical implications of these "generic" relations?

这些“通用”关系的其他实际含义是什么?

Generic foreign keys allow for less intrusive relations between various applications. For example, let's say we pulled the Comment model out into it's own app named chatterly. Now we want to create another application named noise_nimbuswhere people store their music to share with others.

通用外键允许在各种应用程序之间减少侵入性关系。例如,假设我们将 Comment 模型拉出到它自己的名为chatterly. 现在我们要创建另一个应用程序,命名为noise_nimbus人们存储他们的音乐以与他人分享。

What if we want to add comments to those songs? Well, we can just draw a generic relation:

如果我们想为这些歌曲添加评论怎么办?好吧,我们可以画一个通用的关系:

# 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)

I hope you guys found this helpful as I would have loved to have come across something that showed me the more realistic application of GenericForeignKeyand GenericRelationfields.

我希望你们发现这很有帮助,因为我很想遇到一些向我展示GenericForeignKeyGenericRelation领域更现实应用的东西。

Is this too good to be true?

这是不是太好了?

As with anything in life, there are pros and cons. Anytime you add more code and more abstraction, the underlying processes becomes heavier and a bit slower. Adding generic relations can add a little bit of a performance dampener despite the fact it will try and smart cache its results. All in all, it comes down to whether the cleanliness and simplicity outweighs the small performance costs. For me, the answer is a million times yes.

就像生活中的任何事情一样,有利有弊。每当您添加更多代码和更多抽象时,底层流程就会变得更重且更慢。添加通用关系可以增加一点性能阻尼器,尽管它会尝试智能缓存其结果。总而言之,这归结为清洁和简单是否超过了小的性能成本。对我来说,答案是一百万次是。

There is more to the Content Types framework than I have displayed here. There is a whole level of granularity and more verbose usage, but for the average individual, this is how you will be using it 9 out of 10 times in my opinion.

内容类型框架的内容比我在这里展示的要多。有一个完整的粒度级别和更详细的用法,但对于普通人来说,这就是我认为 10 次中有 9 次会使用它的方式。

Generic relationizers(?) beware!

通用关系器(?)当心!

A rather large caveatis that when you use a GenericRelation, if the model which has the GenericRelationapplied (Picture) is deleted, all related (Comment) objects will also be deleted. Or at least as of the time of this writing.

一个相当大的警告是,当您使用 a 时GenericRelation,如果删除了GenericRelation应用 ( Picture)的模型,所有相关的 ( Comment) 对象也将被删除。或者至少在撰写本文时。

回答by Jeff Sheffield

Ok well the direct answer to your question: ( from the django source code ) is: Media Types parsing according to RFC 2616, section 3.7.

好吧,您的问题的直接答案是:(来自 django 源代码)是: 根据 RFC 2616 第 3.7 节解析媒体类型。

Which is the tears way of saying that it reads/allows-you-to-modify/passes along the 'Content-type'httpd header.

这是说它读取/允许您修改/传递“内容类型”httpd 标头的眼泪方式。

However, you are asking for a more practice usage example. I have 2 suggestions for you:

但是,您要求提供更多实践使用示例。我有2个建议给你:

1: examine this code

1:检查这段代码

def index(request):
   media_type='text/html'
   if request.META.has_key('CONTENT_TYPE'):
      media_type = request.META['CONTENT_TYPE'].split(';')[0]

   if media_type.lower() == 'application/json':
      return HttpResponse("""{ "ResponseCode": "Success"}""", content_type="application/json; charset=UTF-8")

   return HttpResponse("<h1>regular old joe</h1>");

2: remember django is python, and as such it wields the power of the python community. There are 2 awesome RESTFul plugins to django. So if you want to see how deep the rabbit whole goes you can check out.

2:记住django是python,因此它运用了python社区的力量。django 有 2 个很棒的 RESTFul 插件。因此,如果您想查看整个兔子的深度,可以查看。

I suggest going through the django-rest-framework tutorial which will address 'acting on different content/types' specifically. Note: It is common practice to use the content-type header to 'version' restful API's.

我建议阅读 django-rest-framework 教程,该教程将专门解决“对不同的内容/类型采取行动”的问题。注意:通常的做法是使用 content-type 标头来“版本”restful API 的.