Фреймворк 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 использует его для привязки разрешений пользователей к определенным моделям.
authentication framework
ContentType
Модель ¶
-
класс
ContentType
¶ Каждый экземпляр
ContentType
имеет два поля, которые, вместе взятые, однозначно описывают установленную модель:-
app_label
¶ Имя приложения, частью которого является модель. Это берется из
app_label
атрибута модели и включает только последнюю часть пути импорта Python приложения;django.contrib.contenttypes
, например, становитсяapp_label
офcontenttypes
.
-
model
¶ Имя класса модели.
Дополнительно доступно следующее свойство:
-
name
¶ Удобочитаемое имя типа контента. Это взято из
verbose_name
атрибута модели.
-
Давайте посмотрим на пример, чтобы увидеть, как это работает. Если у вас уже установлено contenttypes
приложение, а затем добавьте его
в
настройки и запустите для его установки, модель будет установлена в вашу базу данных. Вместе с этим будет создан новый экземпляр
со следующими значениями:the sites application
INSTALLED_APPS
manage.py migrate
django.contrib.sites.models.Site
ContentType
Методы на ContentType
инстансах ¶
У каждого ContentType
экземпляра есть методы, которые позволяют вам перейти от
ContentType
экземпляра к модели, которую он представляет, или получить объекты из этой модели:
-
ContentType.
get_object_for_this_type
( ** kwargs ) ¶ Принимает набор допустимых аргументов поиска для модели, которую
ContentType
представляет, и выполняет для этой модели, возвращая соответствующий объект.a get() lookup
-
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 используется
модель с внешним ключом для ; это позволяет
представить такие понятия, как «можно добавить запись в блог» или «можно удалить новость».the permissions system
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_models=False
позволяет получатьContentType
прокси-модели.
-
get_by_natural_key
( app_label , модель ) ¶ Возвращает
ContentType
экземпляр, однозначно идентифицируемый по заданной метке приложения и названию модели. Основная цель этого метода - датьContentType
возможность ссылаться на объекты через естественный ключ во время десериализации.
-
Этот get_for_model()
метод особенно полезен, когда вы знаете, что вам нужно работать с a,
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
модель использовала a,
ForeignKey
ей пришлось бы выбрать одну и только одну модель для хранения тегов. Приложение contenttypes предоставляет специальный тип поля ( GenericForeignKey
), который позволяет обойти это и позволяет устанавливать отношения с любой моделью:
-
класс
GenericForeignKey
¶ Настройка состоит из трех частей
GenericForeignKey
:- Дайте вашу модель есть
ForeignKey
вContentType
. Обычное имя для этого поля - «content_type». - Дайте вашей модели поле, в котором могут храниться значения первичных ключей из моделей, к которым вы будете относиться. Для большинства моделей это означает
PositiveIntegerField
. Обычное имя для этого поля - «object_id». - Дайте вашей модели a
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 базы данных. Поскольку a
GenericForeignKey
не является обычным полевым объектом, эти примеры не будут работать:
# This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)
Точно так же GenericForeignKey
s не появляется в ModelForm
s.
Обратные отношения общего положения ¶
-
класс
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>]>
Вы также можете использовать add()
, create()
или set()
создавать отношения:
>>> t3 = TaggedItem(tag='Web development')
>>> b.tags.add(t3, bulk=False)
>>> b.tags.create(tag='Web framework')
<TaggedItem: Web framework>
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>, <TaggedItem: Web development>, <TaggedItem: Web framework>]>
>>> b.tags.set([t1, t3])
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: Web development>]>
remove()
Вызов будет навалом удалить указанные объекты модели:
>>> b.tags.remove(t3)
>>> b.tags.all()
<QuerySet [<TaggedItem: django>]>
>>> TaggedItem.objects.all()
<QuerySet [<TaggedItem: django>]>
Этот clear()
метод можно использовать для массового удаления всех связанных объектов для экземпляра:
>>> b.tags.clear()
>>> b.tags.all()
<QuerySet []>
>>> TaggedItem.objects.all()
<QuerySet []>
Определение GenericRelation
с помощью
related_query_name
set позволяет запрашивать из связанного объекта:
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
принимает имена полей контента типа и объект-ID в качестве аргументов, так что тоже делает
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 , absolute_max = None , can_delete_extra = True ) ¶ Возвращает
GenericInlineFormSet
usingmodelformset_factory()
.Необходимо указать
ct_field
и,fk_field
если они отличаются от значений по умолчанию,content_type
иobject_id
соответственно. Остальные параметры аналогичны параметрам, задокументированным вmodelformset_factory()
иinlineformset_factory()
.for_concrete_model
Аргумент соответствуетfor_concrete_model
аргументуGenericForeignKey
.Изменено в Django 3.2:absolute_max
Иcan_delete_extra
были добавлены аргументы.
Общие отношения в админке ¶
django.contrib.contenttypes.admin
Модуль обеспечивает
GenericTabularInline
и
GenericStackedInline
(подклассы
GenericInlineModelAdmin
)
Эти классы и функции позволяют использовать общие отношения в формах и в админке. Дополнительную информацию см. В документации по набору форм и администратору .
-
класс
GenericInlineModelAdmin
¶ GenericInlineModelAdmin
Класс наследует все свойства отInlineModelAdmin
класса. Однако он добавляет пару собственных для работы с родовым отношением:-
ct_field
¶ Имя поля
ContentType
внешнего ключа в модели. По умолчаниюcontent_type
.
-
ct_fk_field
¶ Имя целочисленного поля, представляющего идентификатор связанного объекта. По умолчанию
object_id
.
-
-
класс
GenericTabularInline
¶
-
класс
GenericStackedInline
¶ Подклассы
GenericInlineModelAdmin
с составными и табличными макетами соответственно.