Django内容类型到底是如何工作的?

时间:2022-08-02 17:02:34

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内容类型的概念。它给人的感觉非常陈腐,而且最终与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文档中没有提到的地方(似乎什么地方都没有)。

2 个解决方案

#1


231  

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程序员,你的高人一等的智慧告诉你这很糟糕,你可以做得更好。高5 !

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 Comment model and replace them with a GenericForeignKey.

好了,现在我们来仔细看看我们的模型,并重新设计它们,让它们更“可重用”和直观。让我们从删除评论模型上的两个外键开始,用一个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 ForeignKey to ContentType and a PositiveIntegerField for 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.

所以,发生了什么事?我们添加了必要的代码以允许与其他模型的通用关系。请注意,除了GenericForeignKey,还有ContentType的ForeignKey和object_id的PositiveIntegerField。这些字段用于告诉Django这个对象与什么类型的对象有关,以及这个对象的id是什么。实际上,这是有意义的,因为Django需要同时查找这些相关的对象。

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

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

你可能正在寻找无懈可击、一尘不染、直观的代码,这将使圭多·范·罗瑟姆感到骄傲。我得到了你。让我们来看看广义关系场,这样我们就能在这上面画一个漂亮的蝴蝶结。

# 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 shell from your Django project directory).

砰!就像这样,您可以使用这两个模型的注释。实际上,让我们在shell中执行这个操作(类型为python manage)。来自Django项目目录的py shell)。

>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture

# 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!">]

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_nimbus where people store their music to share with others.

通用外键允许不同应用程序之间的入侵关系更小。例如,假设我们将注释模型提取出来放到它自己的应用中,名为chat打赢。现在我们想要创建另一个名为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 GenericForeignKey and GenericRelation fields.

我希望你们觉得这对我很有帮助,因为我很乐意看到一些东西,它向我展示了GenericForeignKey和GenericRelation字段的更现实的应用。

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 gains. 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.

内容类型框架比我在这里显示的更多。有一个完整的粒度级别和更详细的用法,但是对于一般人来说,我认为这是你使用它的9 / 10的方式。

Generic relationizers(?) beware!

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

一个相当大的警告是,当您使用一个泛型关系时,如果应用了泛型关系(图片)的模型被删除,那么所有相关的(注释)对象也将被删除。或者至少在写作的时候。

#2


0  

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:

但是,您需要一个更实际的使用示例。我有两个建议给你:

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有两个很棒的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-res -framework教程,该教程将专门讨论“针对不同的内容/类型进行操作”。注意:通常的做法是将内容类型的头用于“版本”restful API。

#1


231  

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程序员,你的高人一等的智慧告诉你这很糟糕,你可以做得更好。高5 !

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 Comment model and replace them with a GenericForeignKey.

好了,现在我们来仔细看看我们的模型,并重新设计它们,让它们更“可重用”和直观。让我们从删除评论模型上的两个外键开始,用一个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 ForeignKey to ContentType and a PositiveIntegerField for 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.

所以,发生了什么事?我们添加了必要的代码以允许与其他模型的通用关系。请注意,除了GenericForeignKey,还有ContentType的ForeignKey和object_id的PositiveIntegerField。这些字段用于告诉Django这个对象与什么类型的对象有关,以及这个对象的id是什么。实际上,这是有意义的,因为Django需要同时查找这些相关的对象。

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

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

你可能正在寻找无懈可击、一尘不染、直观的代码,这将使圭多·范·罗瑟姆感到骄傲。我得到了你。让我们来看看广义关系场,这样我们就能在这上面画一个漂亮的蝴蝶结。

# 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 shell from your Django project directory).

砰!就像这样,您可以使用这两个模型的注释。实际上,让我们在shell中执行这个操作(类型为python manage)。来自Django项目目录的py shell)。

>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture

# 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!">]

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_nimbus where people store their music to share with others.

通用外键允许不同应用程序之间的入侵关系更小。例如,假设我们将注释模型提取出来放到它自己的应用中,名为chat打赢。现在我们想要创建另一个名为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 GenericForeignKey and GenericRelation fields.

我希望你们觉得这对我很有帮助,因为我很乐意看到一些东西,它向我展示了GenericForeignKey和GenericRelation字段的更现实的应用。

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 gains. 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.

内容类型框架比我在这里显示的更多。有一个完整的粒度级别和更详细的用法,但是对于一般人来说,我认为这是你使用它的9 / 10的方式。

Generic relationizers(?) beware!

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

一个相当大的警告是,当您使用一个泛型关系时,如果应用了泛型关系(图片)的模型被删除,那么所有相关的(注释)对象也将被删除。或者至少在写作的时候。

#2


0  

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:

但是,您需要一个更实际的使用示例。我有两个建议给你:

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有两个很棒的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-res -framework教程,该教程将专门讨论“针对不同的内容/类型进行操作”。注意:通常的做法是将内容类型的头用于“版本”restful API。