Как именно работают типы контента Django?

Мне действительно трудно понять концепцию типов контента Django. Он чувствует себя очень хакерским и, в конечном счете, против того, как Python имеет тенденцию делать вещи. При этом, если я собираюсь использовать Django, то я должен работать в пределах рамок.

поэтому я прихожу сюда, задаваясь вопросом, Может ли кто-нибудь дать практический реальный пример того, как работает тип контента и как вы его реализуете. Почти все учебники (в основном в блогах), которые я рассмотрел, не сделайте большую работу, действительно охватывая концепцию. Кажется, они поднимают, где документация Django остановилась (что кажется нигде).

2 ответов


Итак, вы хотите использовать фреймворк типов контента в своей работе?

# 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 to ContentType и PositiveIntegerField на object_id. Эти поля предназначены для того, чтобы сообщить Django, с каким типом объекта это связано и какой идентификатор для этого объекта. На самом деле, это имеет смысл, потому что Django понадобится как для поиска этих связанных объекты.

Ну, это не очень в стиле Python... его нелепый!

вы, вероятно, ищете герметичный, безупречный, интуитивно понятный код, который сделает Гвидо ван Россум гордиться. Я тебя понимаю. Давайте посмотрим на 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')

БАМ! Так же, как вы можете работать с комментариями для этих двух моделей. На самом деле, давайте продолжим и сделаем это в нашей оболочке (тип python manage.py shell из вашего проекта Django справочник.)

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

я надеюсь, что вы, ребята, нашли это полезным, как я хотел бы наткнуться на что-то, что показало мне более реалистичное применение GenericForeignKey и GenericRelation поля.

это слишком хорошо, чтобы быть правдой?

как и все в жизни, есть плюсы и минусы. Каждый раз, когда вы добавляете больше кода и больше абстракции, базовые процессы становятся тяжелее и немного медленнее. Добавление общие отношения могут добавить немного демпфера производительности, несмотря на то, что он попытается и смарт-кэшировать свои результаты. В общем, все сводится к тому, перевешивает ли чистота и простота небольшие выигрыши в производительности. Для меня ответ в миллион раз "да".

в структуре типов контента больше, чем я показывал здесь. Существует целый уровень детализации и более подробного использования, но для среднего человека это то, как вы будете использовать его 9 в 10 раз на мой взгляд.

универсальный relationizers(?) будьте осторожны!

довольно большая предостережение это когда вы используете GenericRelation, если модель, которая имеет GenericRelation прикладная (Picture) удаляется, все связанные (Comment) объекты также будут удалены. Или, по крайней мере, на момент написания этой статьи.


Ok хорошо прямой ответ на ваш вопрос: (из исходного кода django ) : анализ типов носителей в соответствии с RFC 2616, раздел 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. Есть 2 удивительных RESTful плагинов для django. Так что если вы хотите увидеть, как глубоко кролик весь идет вы можете проверить.

Я предлагаю пройти через учебник django-rest-framework, который будет касаться "действия на разных контентах/типах". Примечание: общая практика использовать заголовок content-type в "версия" restful API.