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

时间:2014-01-03 02:16:12

标签: python django

我真的很难掌握Django内容类型的概念。感觉非常hackish,并且最终反对Python倾向于做事情。话虽这么说,如果我要使用Django,那么我必须在框架的范围内工作。

所以我来到这里想知道是否有人能够提供一个实际的现实世界示例,说明内容类型如何工作以及如何实现它。我所评论的几乎所有教程(主要是在博客上)并没有真正涵盖这个概念。他们似乎在Django文档遗留下来的地方(似乎无处可去)。

2 个答案:

答案 0 :(得分:259)

所以你想在你的工作中使用内容类型框架吗?

首先问自己这个问题:“这些模型中的任何一个是否需要以与其他模型相同的方式相关联和/或我将在未来的时间里以不可预知的方式重复使用这些关系?”我们之所以提出这个问题是因为这就是内容类型框架最擅长的:它创建了模型之间的通用关系。 Blah blah,让我们深入研究一些代码,看看我的意思。

# 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程序员,你的超级智慧告诉你这很糟糕,你可以做得更好。高五!

输入内容类型框架!

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

的Bam!就像那样,你可以使用这两个模型的评论。实际上,让我们继续在shell中执行此操作(从Django项目目录中键入python manage.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!">]

就这么简单。

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

通用外键允许各种应用程序之间的侵入性较小的关系。例如,假设我们将评论模型拉出到它自己的名为chatterly的应用程序中。现在我们要创建另一个名为noise_nimbus的应用程序,人们将其音乐存储起来与其他人共享。

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

# 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字段的内容。

这真是太好了吗?

与生活中的任何事物一样,有利有弊。无论何时添加更多代码和更多抽象,底层进程都会变得更重,速度更慢。添加泛型关系可以增加一点性能阻尼,尽管它会尝试并智能缓存其结果。总而言之,它归结为清洁度和简洁性是否超过了小的性能成本。对我来说,答案是百万次是的。

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

通用关系器(?)要小心!

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

答案 1 :(得分:-1)

好的直接回答你的问题:(来自django源代码)是: Media Types parsing according to RFC 2616, section 3.7.

这是一种流泪的方式,它表示它可以读取/允许您修改/传递'Content-type' httpd标题。

但是,您需要更多练习用法示例。我有2条建议:

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:记住django是python,因此它掌握了python社区的力量。 django有2个很棒的RESTFul插件。所以,如果你想看看整个兔子有多深,你可以看看。

我建议仔细阅读django-rest-framework教程,该教程将专门针对“不同内容/类型”。 注意:通常的做法是使用内容类型标题'version' restful API's