Инфраструктура contenttypes ¶
Django включает приложение, contenttypes
которое позволяет вам перечислить все модели, установленные в проекте Django, обеспечивая общий высокоуровневый интерфейс для работы с моделями.
Предварительный просмотр ¶
Ядром приложения contenttypes является шаблон ContentType
, определенный в django.contrib.contenttypes.models.ContentType
. Экземпляры ContentType
представляют и хранят информацию о моделях, установленных в проекте; новые экземпляры ContentType
автоматически создаются каждый раз при установке новых шаблонов.
Экземпляры ContentType
имеют методы для возврата классов моделей, которые они представляют, и для запроса объектов этих моделей. ContentType
также есть собственный обработчик, который добавляет методы для работы ContentType
и получения экземпляров ContentType
для конкретной модели.
Отношения между вашими моделями ContentType
также могут использоваться для установления «общих» отношений между экземпляром одной из ваших моделей и экземплярами любой другой установленной вами модели.
Установка системы contenttypes ¶
Система типов содержимого включена по умолчанию в список, INSTALLED_APPS
созданный пользователем , но если вы удалили ее или задали свой список вручную , вы можете активировать ее, добавив в свой параметр .django-admin startproject
INSTALLED_APPS
'django.contrib.contenttypes'
INSTALLED_APPS
Обычно рекомендуется установить приложение contenttypes; в этом нуждаются несколько других приложений, поставляемых с Django:
- Приложение администрирования использует его для отслеживания истории каждого объекта, добавленного или измененного через интерфейс администрирования.
- Django используется для разрешения ассоциированных пользователей к определенным моделям.
système d'authentification
Модель ContentType
¶
-
класс
ContentType
¶ Каждый экземпляр
ContentType
имеет два поля, которые, вместе взятые, однозначно описывают установленный шаблон:-
app_label
¶ Имя приложения, частью которого является шаблон. Он исходит из атрибута
app_label
модели и включает только последнюю часть пути импорта Python приложения; Например, атрибутapp_label
изdjango.contrib.contenttypes
становитсяcontenttypes
.
-
model
¶ Имя класса модели.
Дополнительно доступно следующее свойство:
-
name
¶ Читаемое имя типа контента. Это происходит из атрибута
verbose_name
модели.
-
Давайте посмотрим на пример, чтобы увидеть, как это работает. Если приложение contenttypes
уже установлено, то вы добавляете его sites
в настройки INSTALLED_APPS
и запускаете для его установки, шаблон будет установлен в вашей базе данных. В то же время будет создан новый экземпляр со следующими значениями:manage.py migrate
django.contrib.sites.models.Site
ContentType
Методы экземпляра ContentType
¶
У каждого экземпляра ContentType
есть методы, которые позволяют вам перейти от экземпляра ContentType
к модели, которую он представляет, или получить объекты из этой модели:
-
ContentType.
get_object_for_this_type
( ** kwargs ) ¶ Принимает набор допустимых параметров поиска для модели, которая
ContentType
представляет, и выполняет с этой моделью, возвращая соответствующий объект.une recherche get()
-
ContentType.
model_class
() ¶ Возвращает класс модели, представленной этим экземпляром
ContentType
.
Например, мы могли бы найти ContentType
модель User
:
>>> from django.contrib.contenttypes.models import ContentType
>>> user_type = ContentType.objects.get(app_label='auth', model='user')
>>> user_type
<ContentType: user>
Затем используйте его для поиска User
определенного или для доступа к классу модели User
:
>>> user_type.model_class()
<class 'django.contrib.auth.models.User'>
>>> user_type.get_object_for_this_type(username='Guido')
<User: Guido>
Вместе get_object_for_this_type()
и model_class()
позволяют реализовать два чрезвычайно важных варианта использования:
- Используя эти методы, вы можете написать общий код высокого уровня, который запрашивает любую установленную модель; вместо импорта и использования одного конкретного класса модели вы можете передавать переменные
app_label
иmodel
искать объектContentType
во время выполнения, а затем работать с классом модели или извлекать объекты с его помощью. - Вы можете связать другую модель с объектом,
ContentType
чтобы привязать его экземпляры к определенным классам модели, и использовать эти методы для получения доступа к этим классам модели.
Некоторые из приложений, встроенных в Django, используют последний метод. Например, в системе аутентификации Django используется шаблон с внешним ключом для ; это позволяет представлять такие понятия, как «может добавить запись в блог» или «может удалить новость».système de permissions
Permission
ContentType
Permission
Менеджер ContentTypeManager
¶
-
класс
ContentTypeManager
¶ ContentType
также имеет собственный обработчикContentTypeManager
, который добавляет следующие методы:-
clear_cache
() ¶ Очищает внутренний кеш, используемый
ContentType
для отслеживания моделей, для которых были созданы экземплярыContentType
. Вам, вероятно, никогда не понадобится вызывать этот метод самостоятельно; Django автоматически вызывает его при необходимости.
-
get_for_id
( id ) ¶ Найдите один
ContentType
по его идентификатору. Поскольку этот метод использует тот же общий кешget_for_model()
, что и, лучше использовать этот метод, чем обычно .ContentType.objects.get (pk=id)
-
get_for_model
( модель , for_concrete_model = True ) ¶ Принимает либо класс модели, либо экземпляр модели и возвращает экземпляр,
ContentType
представляющий эту модель.for_concrete_model=False
позволяет получить экземплярContentType
прокси-модели.
-
get_for_models
( * модели , for_concrete_models = True ) ¶ Принимает различное количество классов модели и возвращает словарь, связывающий классы модели с экземплярами,
ContentType
которые их представляют.for_concrete_model=False
позволяет получать экземплярыContentType
прокси-моделей.
-
get_by_natural_key
( app_label , модель ) ¶ Возвращает экземпляр,
ContentType
однозначно идентифицируемый по заданной метке приложения и имени шаблона. Основная цель этого метода - позволить объектамContentType
ссылаться на естественный ключ во время десериализации.
-
Этот метод get_for_model()
особенно полезен, когда вы знаете, что с ним нужно работать, ContentType
но не хотите беспокоиться о получении метаданных модели для ручного поиска:
>>> from django.contrib.auth.models import User
>>> ContentType.objects.get_for_model(User)
<ContentType: user>
Общие отношения ¶
Добавление внешнего ключа из одной из ваших собственных моделей в одну ContentType
позволяет модели эффективно связываться с другим классом модели, как в примере модели Permission
выше. Но можно пойти еще дальше и использовать, ContentType
чтобы разрешить истинные общие отношения (иногда называемые «полиморфами») между моделями.
Например, мы могли бы использовать его для такой системы маркировки, как эта
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
return self.tag
ForeignKey
Обычный ключ может «указывать» только на один другой шаблон, а это означает, что если в шаблоне TaggedItem
используется ключ ForeignKey
, ему придется выбрать один и только один шаблон для хранения связанных меток. Приложение contenttypes предоставляет специальный тип поля ( GenericForeignKey
), который решает эту проблему и позволяет установить связь с любой моделью:
-
класс
GenericForeignKey
¶ Чтобы настроить
GenericForeignKey
:- Добавьте ключ
ForeignKey
к своей моделиContentType
. Обычное имя для этого поля - content_type. - Добавьте в модель поле, в котором могут храниться значения первичных ключей из моделей, которые будут предметом ссылки. Для большинства моделей это соответствует полю
PositiveIntegerField
. Обычное имя для этого поля - «object_id». - Добавьте ключ в свою модель
GenericForeignKey
, передав ему имена двух полей, описанных выше. Если эти поля имеют имена «content_type» и «object_id», вы можете опустить их, так как это имена полей по умолчанию, которыеGenericForeignKey
будут искать.
-
for_concrete_model
¶ Если этот атрибут действителен
False
, поле сможет ссылаться на прокси-модели. По умолчанию этоTrue
. Это перекликается настройкиfor_concrete_model
изget_for_model()
.
- Добавьте ключ
Совместимость типов первичного ключа
Поле object_id
не обязательно должно быть того же типа, что и поля первичного ключа связанных моделей, но их значения первичного ключа должны быть способны преобразовываться в тот же тип, что и поле, с object_id
помощью их метода get_db_prep_value()
.
Например, если вы хотите разрешить общие отношения моделей с полями первичного ключа IntegerField
или CharField
, вы можете использовать CharField
в object_id
качестве типа поля модели, поскольку целые числа могут быть преобразованы в строки с помощью get_db_prep_value()
.
Для максимальной гибкости вы можете использовать поле, TextField
которое не имеет определенной максимальной длины, но это может привести к значительному снижению производительности в зависимости от механизма базы данных.
Не существует универсального решения для наилучшего типа поля. Вам необходимо оценить модели, которые вы планируете связать, и определить, какое решение будет наиболее эффективным для вашего варианта использования.
Сериализация ссылок на объекты ContentType
Если вы сериализуете данные (например, при генерации fixtures
) из модели, которая реализует общие отношения, вам, вероятно, следует использовать естественный ключ для уникальной идентификации связанных объектов ContentType
. См. Естественные ключи и дополнительную информацию.dumpdata --natural-foreign
Это активирует API, аналогичный тому, который используется для ForeignKey
обычного ключа ; у каждого TaggedItem
будет поле, content_object
которое возвращает объект, с которым он связан, и вы также можете присвоить значение этому полю или использовать его при создании TaggedItem
:
>>> from django.contrib.auth.models import User
>>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save()
>>> t.content_object
<User: Guido>
Если связанный объект удаляется, поля content_type
и object_id
сохраняют свою первоначальную стоимость и поля GenericForeignKey
возвращается None
:
>>> guido.delete()
>>> t.content_object # returns None
Из-за способа GenericForeignKey
реализации вы не можете использовать эти поля напрямую с фильтрами ( filter()
и exclude()
, например) через API базы данных. В качестве ключевого GenericForeignKey
не является нормальным объектом поля, эти примеры не будут работать не :
# This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)
Точно так же ключи GenericForeignKey
не появляются в формах ModelForm
.
Обратные родовые отношения ¶
-
класс
GenericRelation
¶ Отношения связанного объекта с этим объектом по умолчанию не существует. При определении
related_query_name
отношения создается из связанного с ним объекта. Это позволяет запрашивать и фильтровать связанный объект.
Если вы знаете, какие модели вы будете использовать чаще всего, вы также можете добавить общую «обратную» связь, чтобы включить дополнительный API. Например :
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
class Bookmark(models.Model):
url = models.URLField()
tags = GenericRelation(TaggedItem)
Bookmark
Каждый экземпляр будет иметь атрибут tags
, который можно использовать для получения TaggedItems
связанных с ним объектов :
>>> b = Bookmark(url='https://www.djangoproject.com/')
>>> b.save()
>>> t1 = TaggedItem(content_object=b, tag='django')
>>> t1.save()
>>> t2 = TaggedItem(content_object=b, tag='python')
>>> t2.save()
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
Установив атрибут related_query_name
из GenericRelation
, это позволяет запрос от связанного объекта:
tags = GenericRelation(TaggedItem, related_query_name='bookmark')
Это позволяет выполнять фильтрацию, сортировку или другие операции запроса на Bookmark
from TaggedItem
:
>>> # Get all tags belonging to bookmarks containing `django` in the url
>>> TaggedItem.objects.filter(bookmark__url__contains='django')
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
Если вы не добавите related_query_name
, вы можете выполнить те же типы поиска вручную:
>>> bookmarks = Bookmark.objects.filter(url__contains='django')
>>> bookmark_type = ContentType.objects.get_for_model(Bookmark)
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
Так же, как и GenericForeignKey
принятие имен полей типа контента и идентификатора объекта в качестве параметров GenericRelation
; Если модель, имеющая общий внешний ключ, не использует имена по умолчанию для этих полей, вы должны передать ей имена полей при создании отношения GenericRelation
. Например, если в TaggedItem
упомянутой выше модели использовались именованные поля content_type_fk
и object_primary_key
для создания своего универсального внешнего ключа, то GenericRelation
обратная связь должна быть определена следующим образом:
tags = GenericRelation(
TaggedItem,
content_type_field='content_type_fk',
object_id_field='object_primary_key',
)
Также обратите внимание, что если вы удалите объект, имеющий отношение GenericRelation
, все объекты, имеющие ключ, GenericForeignKey
указывающий на него, также будут удалены. В приведенном выше примере это означает, что если объект Bookmark
был удален, все объекты, TaggedItem
указывающие на него, будут удалены одновременно.
В отличие от ForeignKey
, GenericForeignKey
не принимает параметр on_delete
для настройки этого поведения; если хотите, вы можете избежать каскада удаления, не определяя отношения GenericRelation
; сигнал может обеспечивать различное поведение pre_delete
.
Общие отношения и агрегирование ¶
" База данных API агрегации Django работает с отношениями GenericRelation
. Например, вы можете узнать, сколько «тегов» определено для всех закладок:
>>> Bookmark.objects.aggregate(Count('tags'))
{'tags__count': 3}
Родовые отношения в формах ¶
Модуль django.contrib.contenttypes.forms
обеспечивает:
BaseGenericInlineFormSet
- Фабрика группы форм ,,
generic_inlineformset_factory()
для использования сGenericForeignKey
.
-
класс
BaseGenericInlineFormSet
¶
-
generic_inlineformset_factory
( model , form = ModelForm , formset = BaseGenericInlineFormSet , ct_field = "content_type" , fk_field = "object_id" , fields = None , exclude = None , extra = 3 , can_order = False , can_delete = True , max_num = None , formfield_callback = None , validate_max = False , for_concrete_model = True , min_num = None , validate_min = False ) ¶ Возвращает один
GenericInlineFormSet
используяmodelformset_factory()
.Необходимо указать
ct_field
и,fk_field
если они отличаются от значений по умолчанию, соответственноcontent_type
иobject_id
. Остальные параметры аналогичны параметрам, задокументированным вmodelformset_factory()
иinlineformset_factory()
.Параметр
for_concrete_model
соответствует параметруfor_concrete_model
изGenericForeignKey
.
Общие отношения в интерфейсе администрирования ¶
Модуль django.contrib.contenttypes.admin
предоставляет GenericTabularInline
и GenericStackedInline
(подклассы GenericInlineModelAdmin
)
Эти классы и функции позволяют использовать общие отношения в формах и интерфейсе администрирования. Дополнительную информацию см. В документации по формам сгруппированных моделей и интерфейсу администратора .
-
класс
GenericInlineModelAdmin
¶ Класс
GenericInlineModelAdmin
наследует все свойства классаInlineModelAdmin
. Однако для работы с родовыми отношениями она добавляет еще несколько:-
ct_field
¶ Имя поля внешнего ключа
ContentType
в шаблоне. По умолчаниюcontent_type
.
-
ct_fk_field
¶ Имя целочисленного поля, представляющего идентификатор связанного объекта. По умолчанию
object_id
.
-
-
класс
GenericTabularInline
¶
-
класс
GenericStackedInline
¶ Подклассы
GenericInlineModelAdmin
с составными и табличными макетами соответственно.