“Django/docs/3.0.x/ref/contrib/contenttypes”的版本间差异

来自菜鸟教程
Django/docs/3.0.x/ref/contrib/contenttypes
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:内容类型框架 — Django 文档}}
 
<div id="module-django.contrib.contenttypes" class="section">
 
<div id="module-django.contrib.contenttypes" class="section">
  
 
<span id="the-contenttypes-framework"></span>
 
<span id="the-contenttypes-framework"></span>
= The contenttypes framework =
+
= 内容类型框架 =
  
Django includes a [[#module-django.contrib.contenttypes|<code>contenttypes</code>]] application that can
+
Django 包含一个 [[#module-django.contrib.contenttypes|contenttypes]] 应用程序,该应用程序可以跟踪安装在 Django 驱动的项目中的所有模型,提供用于处理模型的高级通用接口。
track all of the models installed in your Django-powered project, providing a
 
high-level, generic interface for working with your models.
 
  
 
<div id="overview" class="section">
 
<div id="overview" class="section">
  
== 概况 ==
+
== 概览 ==
  
At the heart of the contenttypes application is the
+
contenttypes 应用程序的核心是 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 模型,它位于 <code>django.contrib.contenttypes.models.ContentType</code>[[#django.contrib.contenttypes.models.ContentType|ContentType]] 的实例表示并存储有关安装在项目中的模型的信息,并且每当安装新模型时都会自动创建 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 的新实例。
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] model, which lives at
 
<code>django.contrib.contenttypes.models.ContentType</code>. Instances of
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] represent and store
 
information about the models installed in your project, and new instances of
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] are automatically
 
created whenever new models are installed.
 
  
Instances of [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] have
+
[[#django.contrib.contenttypes.models.ContentType|ContentType]] 的实例具有返回它们所代表的模型类以及从这些模型中查询对象的方法。 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 还有一个 [[../../../topics/db/managers#custom-managers|自定义管理器]] ,它添加了使用 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 和获取特定模型的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例的方法。
methods for returning the model classes they represent and for querying objects
 
from those models. [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]
 
also has a [[../../../topics/db/managers#custom-managers|<span class="std std-ref">custom manager</span>]] that adds methods for
 
working with [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] and for
 
obtaining instances of [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]
 
for a particular model.
 
  
Relations between your models and
+
您的模型与 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 之间的关系还可用于启用您的模型之一的实例与您已安装的任何模型的实例之间的“通用”关系。
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] can also be used to
 
enable &quot;generic&quot; relationships between an instance of one of your
 
models and instances of any model you have installed.
 
  
  
第37行: 第21行:
 
<div id="installing-the-contenttypes-framework" class="section">
 
<div id="installing-the-contenttypes-framework" class="section">
  
== Installing the contenttypes framework ==
+
== 安装内容类型框架 ==
  
The contenttypes framework is included in the default
+
contenttypes 框架包含在由 <code>django-admin startproject</code> 创建的默认 [[#id1|:setting:`INSTALLED_APPS`]] 列表中,但如果您已将其删除或手动设置 [[#id3|:setting: `INSTALLED_APPS`]] 列表,您可以通过将 <code>'django.contrib.contenttypes'</code> 添加到 [[#id5|:setting:`INSTALLED_APPS`]] 设置来启用它。
[[../../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] list created by <code>django-admin startproject</code>,
 
but if you've removed it or if you manually set up your
 
[[../../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] list, you can enable it by adding
 
<code>'django.contrib.contenttypes'</code> to your [[../../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] setting.
 
  
It's generally a good idea to have the contenttypes framework
+
安装 contenttypes 框架通常是个好主意; 一些 Django 的其他捆绑应用程序需要它:
installed; several of Django's other bundled applications require it:
 
  
* The admin application uses it to log the history of each object added or changed through the admin interface.
+
* 管理应用程序使用它来记录通过管理界面添加或更改的每个对象的历史记录。
* Django's [[../../../topics/auth/index#module-django.contrib|<code>authentication framework</code>]] uses it to tie user permissions to specific models.
+
* Django [[../../../topics/auth/index#module-django.contrib|身份验证框架]] 使用它来将用户权限绑定到特定模型。
  
  
第55行: 第34行:
 
<div id="the-contenttype-model" class="section">
 
<div id="the-contenttype-model" class="section">
  
== The <code>ContentType</code> model ==
+
== ContentType型号 ==
  
 
<dl>
 
<dl>
<dt>''class'' <code>ContentType</code></dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">ContentType</span></span></dt>
<dd><p>Each instance of [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]
+
<dd><p>[[#django.contrib.contenttypes.models.ContentType|ContentType]] 的每个实例都有两个字段,它们共同唯一地描述了一个已安装的模型:</p>
has two fields which, taken together, uniquely describe an installed
 
model:</p>
 
 
<dl>
 
<dl>
<dt><code>app_label</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">app_label</span></span></dt>
<dd><p>The name of the application the model is part of. This is taken from
+
<dd><p>模型所属的应用程序的名称。 这取自模型的 [[#django.contrib.contenttypes.models.ContentType.app_label|app_label]] 属性,仅包含应用程序 Python 导入路径的 ''last'' 部分; 例如,<code>django.contrib.contenttypes</code>成为<code>contenttypes</code>的[[#django.contrib.contenttypes.models.ContentType.app_label|app_label]]</p></dd></dl>
the [[#django.contrib.contenttypes.models.ContentType.app_label|<code>app_label</code>]] attribute of the model, and includes only the
 
''last'' part of the application's Python import path;
 
<code>django.contrib.contenttypes</code>, for example, becomes an
 
[[#django.contrib.contenttypes.models.ContentType.app_label|<code>app_label</code>]] of <code>contenttypes</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>model</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">model</span></span></dt>
<dd><p>The name of the model class.</p></dd></dl>
+
<dd><p>模型类的名称。</p></dd></dl>
  
<p>Additionally, the following property is available:</p>
+
<p>此外,以下属性可用:</p>
 
<dl>
 
<dl>
<dt><code>name</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">name</span></span></dt>
<dd><p>The human-readable name of the content type. This is taken from the
+
<dd><p>内容类型的可读名称。 这取自模型的 [[../../models/fields#django.db.models.Field|verbose_name]] 属性。</p></dd></dl>
[[../../models/fields#django.db.models.Field|<code>verbose_name</code>]]
 
attribute of the model.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
Let's look at an example to see how this works. If you already have
+
让我们看一个例子,看看它是如何工作的。 如果您已经安装了 [[#module-django.contrib.contenttypes|contenttypes]] 应用程序,然后将 [[../sites#module-django.contrib|站点应用程序]] 添加到您的 [[#id7|:setting:`INSTALLED_APPS`]] 设置并运行 <code>manage.py migrate</code>要安装它,模型 [[../sites#django.contrib.sites.models|django.contrib.sites.models.Site]] 将安装到您的数据库中。 随之而来的是一个新的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例,其值如下:
the [[#module-django.contrib.contenttypes|<code>contenttypes</code>]] application installed, and then add
 
[[../sites#module-django.contrib|<code>the sites application</code>]] to your
 
[[../../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] setting and run <code>manage.py migrate</code> to install it,
 
the model [[../sites#django.contrib.sites.models|<code>django.contrib.sites.models.Site</code>]] will be installed into
 
your database. Along with it a new instance of
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] will be
 
created with the following values:
 
  
* [[#django.contrib.contenttypes.models.ContentType.app_label|<code>app_label</code>]] will be set to <code>'sites'</code> (the last part of the Python path <code>django.contrib.sites</code>).
+
* [[#django.contrib.contenttypes.models.ContentType.app_label|app_label]] 将设置为 <code>'sites'</code>(Python 路径 <code>django.contrib.sites</code> 的最后一部分)。
* [[#django.contrib.contenttypes.models.ContentType.model|<code>model</code>]] will be set to <code>'site'</code>.
+
* [[#django.contrib.contenttypes.models.ContentType.model|型号]]将设置为<code>'site'</code>
  
  
第98行: 第62行:
 
<div id="methods-on-contenttype-instances" class="section">
 
<div id="methods-on-contenttype-instances" class="section">
  
== Methods on <code>ContentType</code> instances ==
+
== ContentType 实例上的方法 ==
  
Each [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instance has
+
每个 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例都有一些方法,允许您从 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例获取它所代表的模型,或者从该模型中检索对象:
methods that allow you to get from a
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instance to the
 
model it represents, or to retrieve objects from that model:
 
  
; <code>ContentType.</code><code>get_object_for_this_type</code><span class="sig-paren">(</span>''<span class="o">**</span><span class="n">kwargs</span>''<span class="sig-paren">)</span>
+
; <span class="sig-prename descclassname"><span class="pre">ContentType.</span></span><span class="sig-name descname"><span class="pre">get_object_for_this_type</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">kwargs</span></span>''<span class="sig-paren">)</span>
: Takes a set of valid [[../../../topics/db/queries#field-lookups-intro|<span class="std std-ref">lookup arguments</span>]] for the model the [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] represents, and does [[../../models/querysets#django.db.models.query.QuerySet|<code>a get() lookup</code>]] on that model, returning the corresponding object.
+
: 为 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 表示的模型获取一组有效的 [[../../../topics/db/queries#field-lookups-intro|查找参数]] ,并在该模型上执行 [[../../models/querysets#django.db.models.query.QuerySet|get() 查找]] ,返回相应的对象。
  
; <code>ContentType.</code><code>model_class</code><span class="sig-paren">(</span><span class="sig-paren">)</span>
+
; <span class="sig-prename descclassname"><span class="pre">ContentType.</span></span><span class="sig-name descname"><span class="pre">model_class</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span>
: Returns the model class represented by this [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instance.
+
: 返回由此 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例表示的模型类。
  
For example, we could look up the
+
例如,我们可以查找 [[../auth#django.contrib.auth.models|User]] 模型的 [[#django.contrib.contenttypes.models.ContentType|ContentType]]
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] for the
 
[[../auth#django.contrib.auth.models|<code>User</code>]] model:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第119行: 第78行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.contrib.contenttypes.models import ContentType
+
<syntaxhighlight lang="python">>>> from django.contrib.contenttypes.models import ContentType
&gt;&gt;&gt; user_type = ContentType.objects.get(app_label='auth', model='user')
+
>>> user_type = ContentType.objects.get(app_label='auth', model='user')
&gt;&gt;&gt; user_type
+
>>> user_type
&lt;ContentType: user&gt;</pre>
+
<ContentType: user></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
And then use it to query for a particular
+
然后使用它来查询特定的 [[../auth#django.contrib.auth.models|User]],或访问 <code>User</code> 模型类:
[[../auth#django.contrib.auth.models|<code>User</code>]], or to get access
 
to the <code>User</code> model class:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第135行: 第92行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; user_type.model_class()
+
<syntaxhighlight lang="python">>>> user_type.model_class()
&lt;class 'django.contrib.auth.models.User'&gt;
+
<class 'django.contrib.auth.models.User'>
&gt;&gt;&gt; user_type.get_object_for_this_type(username='Guido')
+
>>> user_type.get_object_for_this_type(username='Guido')
&lt;User: Guido&gt;</pre>
+
<User: Guido></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Together,
+
[[#django.contrib.contenttypes.models.ContentType.get_object_for_this_type|get_object_for_this_type()]] [[#django.contrib.contenttypes.models.ContentType.model_class|model_class()]] 一起实现了两个极其重要的用例:
[[#django.contrib.contenttypes.models.ContentType.get_object_for_this_type|<code>get_object_for_this_type()</code>]]
 
and [[#django.contrib.contenttypes.models.ContentType.model_class|<code>model_class()</code>]] enable
 
two extremely important use cases:
 
  
# Using these methods, you can write high-level generic code that performs queries on any installed model -- instead of importing and using a single specific model class, you can pass an <code>app_label</code> and <code>model</code> into a [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] lookup at runtime, and then work with the model class or retrieve objects from it.
+
# 使用这些方法,您可以编写对任何已安装模型执行查询的高级通用代码——而不是导入和使用单个特定模型类,您可以将 <code>app_label</code> <code>model</code> 传递到[[#django.contrib.contenttypes.models.ContentType|ContentType]] 在运行时查找,然后使用模型类或从中检索对象。
# You can relate another model to [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] as a way of tying instances of it to particular model classes, and use these methods to get access to those model classes.
+
# 您可以将另一个模型与 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 相关联,作为将其实例绑定到特定模型类的一种方式,并使用这些方法来访问这些模型类。
  
Several of Django's bundled applications make use of the latter technique.
+
Django 的一些捆绑应用程序使用了后一种技术。 比如Django的认证框架中的[[../auth#django.contrib.auth.models|权限系统]]使用的是[[../auth#django.contrib.auth.models|Permission]]模型,外键为[[#django.contrib.contenttypes.models.ContentType|ContentType]]; 这让 [[../auth#django.contrib.auth.models|Permission]] 表示“可以添加博客条目”或“可以删除新闻报道”等概念。
For example,
 
[[../auth#django.contrib.auth.models|<code>the permissions system</code>]] in
 
Django's authentication framework uses a
 
[[../auth#django.contrib.auth.models|<code>Permission</code>]] model with a foreign
 
key to [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]; this lets
 
[[../auth#django.contrib.auth.models|<code>Permission</code>]] represent concepts like
 
&quot;can add blog entry&quot; or &quot;can delete news story&quot;.
 
  
 
<div id="the-contenttypemanager" class="section">
 
<div id="the-contenttypemanager" class="section">
  
=== The <code>ContentTypeManager</code> ===
+
=== ContentTypeManager ===
  
 
<dl>
 
<dl>
<dt>''class'' <code>ContentTypeManager</code></dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">ContentTypeManager</span></span></dt>
<dd><p>[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] also has a custom
+
<dd><p>[[#django.contrib.contenttypes.models.ContentType|ContentType]] 还有一个自定义管理器,[[#django.contrib.contenttypes.models.ContentTypeManager|ContentTypeManager]],它增加了以下方法:</p>
manager, [[#django.contrib.contenttypes.models.ContentTypeManager|<code>ContentTypeManager</code>]],
 
which adds the following methods:</p>
 
 
<dl>
 
<dl>
<dt><code>clear_cache</code><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">clear_cache</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>Clears an internal cache used by
+
<dd><p>清除 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 使用的内部缓存,以跟踪已为其创建 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例的模型。 您可能永远不需要自己调用此方法; Django 会在需要时自动调用它。</p></dd></dl>
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] to keep track
 
of models for which it has created
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instances. You
 
probably won't ever need to call this method yourself; Django will call
 
it automatically when it's needed.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_for_id</code><span class="sig-paren">(</span>''<span class="n">id</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_for_id</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">id</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Lookup a [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] by ID.
+
<dd><p>按 ID 查找 [[#django.contrib.contenttypes.models.ContentType|ContentType]]。 由于此方法使用与 [[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|get_for_model()]] 相同的共享缓存,因此优先使用此方法而不是通常的 <code>ContentType.objects.get(pk=id)</code></p></dd></dl>
Since this method uses the same shared cache as
 
[[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|<code>get_for_model()</code>]],
 
it's preferred to use this method over the usual
 
<code>ContentType.objects.get(pk=id)</code></p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_for_model</code><span class="sig-paren">(</span>''<span class="n">model</span>'', ''<span class="n">for_concrete_model</span><span class="o">=</span><span class="default_value">True</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_for_model</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">model</span></span>'', ''<span class="n"><span class="pre">for_concrete_model</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Takes either a model class or an instance of a model, and returns the
+
<dd><p>采用模型类或模型实例,并返回表示该模型的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例。 <code>for_concrete_model=False</code> 允许获取代理模型的 [[#django.contrib.contenttypes.models.ContentType|ContentType]]</p></dd></dl>
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instance
 
representing that model. <code>for_concrete_model=False</code> allows fetching
 
the [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] of a proxy
 
model.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_for_models</code><span class="sig-paren">(</span>''<span class="o">*</span><span class="n">models</span>'', ''<span class="n">for_concrete_models</span><span class="o">=</span><span class="default_value">True</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_for_models</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">models</span></span>'', ''<span class="n"><span class="pre">for_concrete_models</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Takes a variadic number of model classes, and returns a dictionary
+
<dd><p>采用可变数量的模型类,并返回一个将模型类映射到代表它们的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例的字典。 <code>for_concrete_models=False</code> 允许获取代理模型的 [[#django.contrib.contenttypes.models.ContentType|ContentType]]</p></dd></dl>
mapping the model classes to the
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] instances
 
representing them. <code>for_concrete_models=False</code> allows fetching the
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] of proxy
 
models.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_by_natural_key</code><span class="sig-paren">(</span>''<span class="n">app_label</span>'', ''<span class="n">model</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_by_natural_key</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">app_label</span></span>'', ''<span class="n"><span class="pre">model</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns the [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]
+
<dd><p>返回由给定的应用程序标签和模型名称唯一标识的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 实例。 此方法的主要目的是允许在反序列化期间通过 [[../../../topics/serialization#topics-serialization-natural-keys|自然键]] 引用 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 对象。</p></dd></dl>
instance uniquely identified by the given application label and model
 
name. The primary purpose of this method is to allow
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] objects to be
 
referenced via a [[../../../topics/serialization#topics-serialization-natural-keys|<span class="std std-ref">natural key</span>]]
 
during deserialization.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
The [[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|<code>get_for_model()</code>]] method is especially
+
[[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|get_for_model()]] 方法在您知道需要使用 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 但不想麻烦获取模型的元数据以执行手动查找时特别有用:
useful when you know you need to work with a
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] but don't
 
want to go to the trouble of obtaining the model's metadata to perform a manual
 
lookup:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第223行: 第141行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.contrib.auth.models import User
+
<syntaxhighlight lang="python">>>> from django.contrib.auth.models import User
&gt;&gt;&gt; ContentType.objects.get_for_model(User)
+
>>> ContentType.objects.get_for_model(User)
&lt;ContentType: user&gt;</pre>
+
<ContentType: user></syntaxhighlight>
  
 
</div>
 
</div>
第237行: 第155行:
 
<div id="generic-relations" class="section">
 
<div id="generic-relations" class="section">
  
<span id="id1"></span>
+
<span id="id9"></span>
== Generic relations ==
+
== 通用关系 ==
  
Adding a foreign key from one of your own models to
+
将您自己模型中的一个外键添加到 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 允许您的模型有效地将自身绑定到另一个模型类,如上面的 [[../auth#django.contrib.auth.models|Permission]] 模型示例所示。 但是可以更进一步,使用 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 来实现模型之间真正的通用(有时称为“多态”)关系。
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] allows your model to
 
effectively tie itself to another model class, as in the example of the
 
[[../auth#django.contrib.auth.models|<code>Permission</code>]] model above. But it's possible
 
to go one step further and use
 
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] to enable truly
 
generic (sometimes called &quot;polymorphic&quot;) relationships between models.
 
  
For example, it could be used for a tagging system like so:
+
例如,它可以用于标记系统,如下所示:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第254行: 第166行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.contrib.contenttypes.fields import GenericForeignKey
+
<syntaxhighlight lang="python">from django.contrib.contenttypes.fields import GenericForeignKey
 
from django.contrib.contenttypes.models import ContentType
 
from django.contrib.contenttypes.models import ContentType
 
from django.db import models
 
from django.db import models
第265行: 第177行:
  
 
     def __str__(self):
 
     def __str__(self):
         return self.tag</pre>
+
         return self.tag</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
A normal [[../../models/fields#django.db.models|<code>ForeignKey</code>]] can only &quot;point
+
一个普通的 [[../../models/fields#django.db.models|ForeignKey]] 只能“指向”另一个模型,这意味着如果 <code>TaggedItem</code> 模型使用 [[../../models/fields#django.db.models|ForeignKey]] 它必须选择一个并且只有一个模型存储标签。 contenttypes 应用程序提供了一个特殊的字段类型 (<code>GenericForeignKey</code>),它可以解决这个问题,并允许与任何模型建立关系:
to&quot; one other model, which means that if the <code>TaggedItem</code> model used a
 
[[../../models/fields#django.db.models|<code>ForeignKey</code>]] it would have to
 
choose one and only one model to store tags for. The contenttypes
 
application provides a special field type (<code>GenericForeignKey</code>) which
 
works around this and allows the relationship to be with any
 
model:
 
  
 
<dl>
 
<dl>
<dt>''class'' <code>GenericForeignKey</code></dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">GenericForeignKey</span></span></dt>
<dd><p>There are three parts to setting up a
+
<dd><p>设置 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 分为三个部分:</p>
[[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]]:</p>
 
 
<ol>
 
<ol>
<li><p>Give your model a [[../../models/fields#django.db.models|<code>ForeignKey</code>]]
+
<li><p>给你的模型一个 [[../../models/fields#django.db.models|ForeignKey]] [[#django.contrib.contenttypes.models.ContentType|ContentType]]。 该字段的常用名称是“content_type”。</p></li>
to [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]. The usual
+
<li><p>为您的模型提供一个字段,该字段可以存储您将要关联的模型的主键值。 对于大多数模型,这意味着 [[../../models/fields#django.db.models|PositiveIntegerField]]。 该字段的常用名称是“object_id”。</p></li>
name for this field is &quot;content_type&quot;.</p></li>
+
<li><p>给你的模型一个 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]],并将上面描述的两个字段的名称传递给它。 如果这些字段被命名为“content_type”和“object_id”,你可以省略它——这些是 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 将寻找的默认字段名称。</p></li></ol>
<li><p>Give your model a field that can store primary key values from the
 
models you'll be relating to. For most models, this means a
 
[[../../models/fields#django.db.models|<code>PositiveIntegerField</code>]]. The usual name
 
for this field is &quot;object_id&quot;.</p></li>
 
<li><p>Give your model a
 
[[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]], and
 
pass it the names of the two fields described above. If these fields
 
are named &quot;content_type&quot; and &quot;object_id&quot;, you can omit this -- those
 
are the default field names
 
[[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]] will
 
look for.</p></li></ol>
 
  
 
<dl>
 
<dl>
<dt><code>for_concrete_model</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">for_concrete_model</span></span></dt>
<dd><p>If <code>False</code>, the field will be able to reference proxy models. Default
+
<dd><p>如果<code>False</code>,该字段将能够引用代理模型。 默认值为 <code>True</code>。 这将 <code>for_concrete_model</code> 参数映射到 [[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|get_for_model()]]</p></dd></dl>
is <code>True</code>. This mirrors the <code>for_concrete_model</code> argument to
 
[[#django.contrib.contenttypes.models.ContentTypeManager.get_for_model|<code>get_for_model()</code>]].</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
 
<div class="admonition-primary-key-type-compatibility admonition">
 
<div class="admonition-primary-key-type-compatibility admonition">
  
Primary key type compatibility
+
主键类型兼容性
  
The &quot;object_id&quot; field doesn't have to be the same type as the
+
“object_id”字段不必与相关模型上的主键字段的类型相同,但它们的主键值必须通过其 [[../../models/fields#django.db.models.Field|get_db_prep_value() 强制转换为与“object_id”字段相同的类型]] 方法。
primary key fields on the related models, but their primary key values
 
must be coercible to the same type as the &quot;object_id&quot; field by its
 
[[../../models/fields#django.db.models.Field|<code>get_db_prep_value()</code>]] method.
 
  
For example, if you want to allow generic relations to models with either
+
例如,如果您想允许具有 [[../../models/fields#django.db.models|IntegerField]] [[../../models/fields#django.db.models|CharField]] 主键字段的模型的通用关系,您可以使用 [[../../models/fields#django.db.models|CharField]] 作为“object_id”字段您的模型,因为整数可以通过 [[../../models/fields#django.db.models.Field|get_db_prep_value()]] 强制转换为字符串。
[[../../models/fields#django.db.models|<code>IntegerField</code>]] or
 
[[../../models/fields#django.db.models|<code>CharField</code>]] primary key fields, you
 
can use [[../../models/fields#django.db.models|<code>CharField</code>]] for the
 
&quot;object_id&quot; field on your model since integers can be coerced to
 
strings by [[../../models/fields#django.db.models.Field|<code>get_db_prep_value()</code>]].
 
  
For maximum flexibility you can use a
+
为了获得最大的灵活性,您可以使用没有定义最大长度的 [[../../models/fields#django.db.models|TextField]],但是这可能会导致显着的性能损失,具体取决于您的数据库后端。
[[../../models/fields#django.db.models|<code>TextField</code>]] which doesn't have a
 
maximum length defined, however this may incur significant performance
 
penalties depending on your database backend.
 
  
There is no one-size-fits-all solution for which field type is best. You
+
对于哪种字段类型最合适,没有一刀切的解决方案。 您应该评估您希望指向的模型,并确定哪种解决方案对您的用例最有效。
should evaluate the models you expect to be pointing to and determine
 
which solution will be most effective for your use case.
 
  
  
第334行: 第213行:
 
<div class="admonition-serializing-references-to-contenttype-objects admonition">
 
<div class="admonition-serializing-references-to-contenttype-objects admonition">
  
Serializing references to <code>ContentType</code> objects
+
序列化对 <code>ContentType</code> 对象的引用
  
If you're serializing data (for example, when generating
+
如果您正在从实现通用关系的模型中序列化数据(例如,在生成 [[../../../topics/testing/tools#django.test.TransactionTestCase|fixtures]] 时),您可能应该使用自然键来唯一标识相关的 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 对象。 有关详细信息,请参阅 [[../../../topics/serialization#topics-serialization-natural-keys|自然键]] <code>dumpdata --natural-foreign</code>
[[../../../topics/testing/tools#django.test.TransactionTestCase|<code>fixtures</code>]]) from a model that implements
 
generic relations, you should probably be using a natural key to uniquely
 
identify related [[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]]
 
objects. See [[../../../topics/serialization#topics-serialization-natural-keys|<span class="std std-ref">natural keys</span>]] and
 
[[../../django-admin#cmdoption-dumpdata-natural-foreign|<code>dumpdata --natural-foreign</code>]] for more information.
 
  
  
 
</div>
 
</div>
This will enable an API similar to the one used for a normal
+
这将启用一个类似于用于普通 [[../../models/fields#django.db.models|ForeignKey]] 的 API; 每个 <code>TaggedItem</code> 都会有一个 <code>content_object</code> 字段,用于返回与其相关的对象,您也可以分配给该字段或在创建 <code>TaggedItem</code> 时使用它:
[[../../models/fields#django.db.models|<code>ForeignKey</code>]];
 
each <code>TaggedItem</code> will have a <code>content_object</code> field that returns the
 
object it's related to, and you can also assign to that field or use it when
 
creating a <code>TaggedItem</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第355行: 第225行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.contrib.auth.models import User
+
<syntaxhighlight lang="python">>>> from django.contrib.auth.models import User
&gt;&gt;&gt; guido = User.objects.get(username='Guido')
+
>>> guido = User.objects.get(username='Guido')
&gt;&gt;&gt; t = TaggedItem(content_object=guido, tag='bdfl')
+
>>> t = TaggedItem(content_object=guido, tag='bdfl')
&gt;&gt;&gt; t.save()
+
>>> t.save()
&gt;&gt;&gt; t.content_object
+
>>> t.content_object
&lt;User: Guido&gt;</pre>
+
<User: Guido></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If the related object is deleted, the <code>content_type</code> and <code>object_id</code> fields
+
如果删除了相关对象,<code>content_type</code> <code>object_id</code> 字段仍设置为其原始值,而 <code>GenericForeignKey</code> 返回 <code>None</code>
remain set to their original values and the <code>GenericForeignKey</code> returns
 
<code>None</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第373行: 第241行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; guido.delete()
+
<syntaxhighlight lang="python">>>> guido.delete()
&gt;&gt;&gt; t.content_object  # returns None</pre>
+
>>> t.content_object  # returns None</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Due to the way [[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]]
+
由于 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 的实现方式,您不能通过数据库 API 直接将这些字段与过滤器(例如 <code>filter()</code> <code>exclude()</code>)一起使用。 因为 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 不是一个普通的字段对象,这些例子将 ''not'' 工作:
is implemented, you cannot use such fields directly with filters (<code>filter()</code>
 
and <code>exclude()</code>, for example) via the database API. Because a
 
[[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]] isn't a
 
normal field object, these examples will ''not'' work:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第389行: 第253行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># This will fail
+
<syntaxhighlight lang="python"># This will fail
&gt;&gt;&gt; TaggedItem.objects.filter(content_object=guido)
+
>>> TaggedItem.objects.filter(content_object=guido)
 
# This will also fail
 
# This will also fail
&gt;&gt;&gt; TaggedItem.objects.get(content_object=guido)</pre>
+
>>> TaggedItem.objects.get(content_object=guido)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Likewise, [[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]]s
+
同样,[[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]]s 不会出现在 [[../../../topics/forms/modelforms#django.forms|ModelForm]]s 中。
does not appear in [[../../../topics/forms/modelforms#django.forms|<code>ModelForm</code>]]s.
 
  
 
<div id="reverse-generic-relations" class="section">
 
<div id="reverse-generic-relations" class="section">
  
=== Reverse generic relations ===
+
=== 反向泛型关系 ===
  
; ''class'' <code>GenericRelation</code>
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">GenericRelation</span></span>
: ;; <code>related_query_name</code>
+
: ;; <span class="sig-name descname"><span class="pre">related_query_name</span></span>
;: The relation on the related object back to this object doesn't exist by default. Setting <code>related_query_name</code> creates a relation from the related object back to this one. This allows querying and filtering from the related object.
+
;: 默认情况下,相关对象与此对象之间的关系不存在。 设置 <code>related_query_name</code> 创建从相关对象回到这个对象的关系。 这允许从相关对象中查询和过滤。
  
If you know which models you'll be using most often, you can also add
+
如果您知道最常使用哪些模型,您还可以添加“反向”通用关系以启用其他 API。 例如:
a &quot;reverse&quot; generic relationship to enable an additional API. For example:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第415行: 第277行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.contrib.contenttypes.fields import GenericRelation
+
<syntaxhighlight lang="python">from django.contrib.contenttypes.fields import GenericRelation
 
from django.db import models
 
from django.db import models
  
 
class Bookmark(models.Model):
 
class Bookmark(models.Model):
 
     url = models.URLField()
 
     url = models.URLField()
     tags = GenericRelation(TaggedItem)</pre>
+
     tags = GenericRelation(TaggedItem)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
<code>Bookmark</code> instances will each have a <code>tags</code> attribute, which can
+
<code>Bookmark</code> 实例每个都有一个 <code>tags</code> 属性,可用于检索其关联的 <code>TaggedItems</code>
be used to retrieve their associated <code>TaggedItems</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第432行: 第293行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; b = Bookmark(url='https://www.djangoproject.com/')
+
<syntaxhighlight lang="python">>>> b = Bookmark(url='https://www.djangoproject.com/')
&gt;&gt;&gt; b.save()
+
>>> b.save()
&gt;&gt;&gt; t1 = TaggedItem(content_object=b, tag='django')
+
>>> t1 = TaggedItem(content_object=b, tag='django')
&gt;&gt;&gt; t1.save()
+
>>> t1.save()
&gt;&gt;&gt; t2 = TaggedItem(content_object=b, tag='python')
+
>>> t2 = TaggedItem(content_object=b, tag='python')
&gt;&gt;&gt; t2.save()
+
>>> t2.save()
&gt;&gt;&gt; b.tags.all()
+
>>> b.tags.all()
&lt;QuerySet [&lt;TaggedItem: django&gt;, &lt;TaggedItem: python&gt;]&gt;</pre>
+
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Defining [[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]] with
+
使用 <code>related_query_name</code> 集定义 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 允许从相关对象查询:
<code>related_query_name</code> set allows querying from the related object:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第451行: 第311行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>tags = GenericRelation(TaggedItem, related_query_name='bookmark')</pre>
+
<syntaxhighlight lang="python">tags = GenericRelation(TaggedItem, related_query_name='bookmark')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This enables filtering, ordering, and other query operations on <code>Bookmark</code>
+
这可以从 <code>TaggedItem</code> 启用对 <code>Bookmark</code> 的过滤、排序和其他查询操作:
from <code>TaggedItem</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第463行: 第322行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; # Get all tags belonging to bookmarks containing `django` in the url
+
<syntaxhighlight lang="python">>>> # Get all tags belonging to bookmarks containing `django` in the url
&gt;&gt;&gt; TaggedItem.objects.filter(bookmark__url__contains='django')
+
>>> TaggedItem.objects.filter(bookmark__url__contains='django')
&lt;QuerySet [&lt;TaggedItem: django&gt;, &lt;TaggedItem: python&gt;]&gt;</pre>
+
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Of course, if you don't add the <code>related_query_name</code>, you can do the
+
当然,如果不添加<code>related_query_name</code>,也可以手动进行相同类型的查找:
same types of lookups manually:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第477行: 第335行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; bookmarks = Bookmark.objects.filter(url__contains='django')
+
<syntaxhighlight lang="python">>>> bookmarks = Bookmark.objects.filter(url__contains='django')
&gt;&gt;&gt; bookmark_type = ContentType.objects.get_for_model(Bookmark)
+
>>> bookmark_type = ContentType.objects.get_for_model(Bookmark)
&gt;&gt;&gt; TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
+
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
&lt;QuerySet [&lt;TaggedItem: django&gt;, &lt;TaggedItem: python&gt;]&gt;</pre>
+
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Just as [[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]]
+
正如 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 接受内容类型和对象 ID 字段的名称作为参数一样,[[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 也是如此; 如果具有通用外键的模型对这些字段使用非默认名称,则在为其设置 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 时必须传递字段名称。 例如,如果上面提到的 <code>TaggedItem</code> 模型使用名为 <code>content_type_fk</code> <code>object_primary_key</code> 的字段来创建它的通用外键,那么一个 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 返回给它需要像这样定义:
accepts the names of the content-type and object-ID fields as
 
arguments, so too does
 
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]];
 
if the model which has the generic foreign key is using non-default names
 
for those fields, you must pass the names of the fields when setting up a
 
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]] to it. For example, if the <code>TaggedItem</code> model
 
referred to above used fields named <code>content_type_fk</code> and
 
<code>object_primary_key</code> to create its generic foreign key, then a
 
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]] back to it would need to be defined like so:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第500行: 第349行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>tags = GenericRelation(
+
<syntaxhighlight lang="python">tags = GenericRelation(
 
     TaggedItem,
 
     TaggedItem,
 
     content_type_field='content_type_fk',
 
     content_type_field='content_type_fk',
 
     object_id_field='object_primary_key',
 
     object_id_field='object_primary_key',
)</pre>
+
)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Note also, that if you delete an object that has a
+
另请注意,如果您删除具有 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 的对象,则任何具有 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 指向它的对象也将被删除。 在上面的例子中,这意味着如果一个 <code>Bookmark</code> 对象被删除,任何指向它的 <code>TaggedItem</code> 对象将同时被删除。
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]], any objects
 
which have a [[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]]
 
pointing at it will be deleted as well. In the example above, this means that
 
if a <code>Bookmark</code> object were deleted, any <code>TaggedItem</code> objects pointing at
 
it would be deleted at the same time.
 
  
Unlike [[../../models/fields#django.db.models|<code>ForeignKey</code>]],
+
[[../../models/fields#django.db.models|ForeignKey]] 不同,[[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 不接受 [[../../models/fields#django.db.models.ForeignKey|on_delete]] 参数来自定义此行为; 如果需要,您可以通过不使用 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]] 来避免级联删除,并且可以通过 [[../../signals#django.db.models.signals|pre_delete]] 信号提供替代行为。
[[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]] does not accept
 
an [[../../models/fields#django.db.models.ForeignKey|<code>on_delete</code>]] argument to customize this
 
behavior; if desired, you can avoid the cascade-deletion by not using
 
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]], and alternate
 
behavior can be provided via the [[../../signals#django.db.models.signals|<code>pre_delete</code>]]
 
signal.
 
  
  
第528行: 第366行:
 
<div id="generic-relations-and-aggregation" class="section">
 
<div id="generic-relations-and-aggregation" class="section">
  
=== Generic relations and aggregation ===
+
=== 通用关系和聚合 ===
  
[[../../../topics/db/aggregation|<span class="doc">Django's database aggregation API</span>]] works with a
+
[[../../../topics/db/aggregation|Django 的数据库聚合 API]] 使用 [[#django.contrib.contenttypes.fields.GenericRelation|GenericRelation]]。 例如,您可以找出所有书签有多少个标签:
[[#django.contrib.contenttypes.fields.GenericRelation|<code>GenericRelation</code>]]. For example, you
 
can find out how many tags all the bookmarks have:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第538行: 第374行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; Bookmark.objects.aggregate(Count('tags'))
+
<syntaxhighlight lang="python">>>> Bookmark.objects.aggregate(Count('tags'))
{'tags__count': 3}</pre>
+
{'tags__count': 3}</syntaxhighlight>
  
 
</div>
 
</div>
第549行: 第385行:
 
<div id="generic-relation-in-forms" class="section">
 
<div id="generic-relation-in-forms" class="section">
  
=== Generic relation in forms ===
+
=== 表单中的泛型关系 ===
  
The [[#module-django.contrib.contenttypes.forms|<code>django.contrib.contenttypes.forms</code>]] module provides:
+
[[#module-django.contrib.contenttypes.forms|django.contrib.contenttypes.forms]] 模块提供:
  
 
* [[#django.contrib.contenttypes.forms.BaseGenericInlineFormSet|<code>BaseGenericInlineFormSet</code>]]
 
* [[#django.contrib.contenttypes.forms.BaseGenericInlineFormSet|<code>BaseGenericInlineFormSet</code>]]
* A formset factory, [[#django.contrib.contenttypes.forms.generic_inlineformset_factory|<code>generic_inlineformset_factory()</code>]], for use with [[#django.contrib.contenttypes.fields.GenericForeignKey|<code>GenericForeignKey</code>]].
+
* 表单集工厂 [[#django.contrib.contenttypes.forms.generic_inlineformset_factory|generic_inlineformset_factory()]],与 [[#django.contrib.contenttypes.fields.GenericForeignKey|GenericForeignKey]] 一起使用。
  
; ''class'' <code>BaseGenericInlineFormSet</code>
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">BaseGenericInlineFormSet</span></span>
 
:  
 
:  
  
 
<dl>
 
<dl>
<dt><code>generic_inlineformset_factory</code><span class="sig-paren">(</span>''<span class="n">model</span>'', ''<span class="n">form</span><span class="o">=</span><span class="default_value">ModelForm</span>'', ''<span class="n">formset</span><span class="o">=</span><span class="default_value">BaseGenericInlineFormSet</span>'', ''<span class="n">ct_field</span><span class="o">=</span><span class="default_value">'content_type'</span>'', ''<span class="n">fk_field</span><span class="o">=</span><span class="default_value">'object_id'</span>'', ''<span class="n">fields</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">exclude</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">extra</span><span class="o">=</span><span class="default_value">3</span>'', ''<span class="n">can_order</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">can_delete</span><span class="o">=</span><span class="default_value">True</span>'', ''<span class="n">max_num</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">formfield_callback</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">validate_max</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">for_concrete_model</span><span class="o">=</span><span class="default_value">True</span>'', ''<span class="n">min_num</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">validate_min</span><span class="o">=</span><span class="default_value">False</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">generic_inlineformset_factory</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">model</span></span>'', ''<span class="n"><span class="pre">form</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">ModelForm</span></span>'', ''<span class="n"><span class="pre">formset</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">BaseGenericInlineFormSet</span></span>'', ''<span class="n"><span class="pre">ct_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">'content_type'</span></span>'', ''<span class="n"><span class="pre">fk_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">'object_id'</span></span>'', ''<span class="n"><span class="pre">fields</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">exclude</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">extra</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">3</span></span>'', ''<span class="n"><span class="pre">can_order</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">can_delete</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>'', ''<span class="n"><span class="pre">max_num</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">formfield_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">validate_max</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">for_concrete_model</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>'', ''<span class="n"><span class="pre">min_num</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">validate_min</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns a <code>GenericInlineFormSet</code> using
+
<dd><p>使用 [[../../forms/models#django.forms.models|modelformset_factory()]] 返回 <code>GenericInlineFormSet</code></p>
[[../../forms/models#django.forms.models|<code>modelformset_factory()</code>]].</p>
+
<p>如果 <code>ct_field</code> <code>fk_field</code> 与默认值不同,您必须分别提供 <code>content_type</code> <code>object_id</code>。 其他参数类似于 [[../../forms/models#django.forms.models|modelformset_factory()]] [[../../forms/models#django.forms.models|inlineformset_factory()]] 中记录的参数。</p>
<p>You must provide <code>ct_field</code> and <code>fk_field</code> if they are different from
+
<p><code>for_concrete_model</code> 参数对应于 <code>GenericForeignKey</code> 上的 [[#django.contrib.contenttypes.fields.GenericForeignKey.for_concrete_model|for_concrete_model]] 参数。</p></dd></dl>
the defaults, <code>content_type</code> and <code>object_id</code> respectively. Other
 
parameters are similar to those documented in
 
[[../../forms/models#django.forms.models|<code>modelformset_factory()</code>]] and
 
[[../../forms/models#django.forms.models|<code>inlineformset_factory()</code>]].</p>
 
<p>The <code>for_concrete_model</code> argument corresponds to the
 
[[#django.contrib.contenttypes.fields.GenericForeignKey.for_concrete_model|<code>for_concrete_model</code>]]
 
argument on <code>GenericForeignKey</code>.</p></dd></dl>
 
  
 
<span id="module-django.contrib.contenttypes.admin" class="target"></span>
 
<span id="module-django.contrib.contenttypes.admin" class="target"></span>
第577行: 第406行:
 
<div id="generic-relations-in-admin" class="section">
 
<div id="generic-relations-in-admin" class="section">
  
=== Generic relations in admin ===
+
=== 管理中的通用关系 ===
  
The [[#module-django.contrib.contenttypes.admin|<code>django.contrib.contenttypes.admin</code>]] module provides
+
[[#module-django.contrib.contenttypes.admin|django.contrib.contenttypes.admin]] 模块提供 [[#django.contrib.contenttypes.admin.GenericTabularInline|GenericTabularInline]] [[#django.contrib.contenttypes.admin.GenericStackedInline|GenericStackedInline]][[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|GenericInlineModelAdmin]] 的子类)
[[#django.contrib.contenttypes.admin.GenericTabularInline|<code>GenericTabularInline</code>]] and
 
[[#django.contrib.contenttypes.admin.GenericStackedInline|<code>GenericStackedInline</code>]] (subclasses of
 
[[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|<code>GenericInlineModelAdmin</code>]])
 
  
These classes and functions enable the use of generic relations in forms
+
这些类和函数允许在表单和管理中使用通用关系。 有关更多信息,请参阅 [[../../../topics/forms/modelforms|模型表单集]] [[../admin/index#using-generic-relations-as-an-inline|管理]] 文档。
and the admin. See the [[../../../topics/forms/modelforms|<span class="doc">model formset</span>]] and
 
[[../admin/index#using-generic-relations-as-an-inline|<span class="std std-ref">admin</span>]] documentation for more
 
information.
 
  
 
<dl>
 
<dl>
<dt>''class'' <code>GenericInlineModelAdmin</code></dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">GenericInlineModelAdmin</span></span></dt>
<dd><p>The [[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|<code>GenericInlineModelAdmin</code>]]
+
<dd><p>[[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|GenericInlineModelAdmin]] 类继承了 [[../admin/index#django.contrib.admin|InlineModelAdmin]] 类的所有属性。 但是,它添加了一些自己的用于处理通用关系:</p>
class inherits all properties from an
 
[[../admin/index#django.contrib.admin|<code>InlineModelAdmin</code>]] class. However,
 
it adds a couple of its own for working with the generic relation:</p>
 
 
<dl>
 
<dl>
<dt><code>ct_field</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">ct_field</span></span></dt>
<dd><p>The name of the
+
<dd><p>模型上 [[#django.contrib.contenttypes.models.ContentType|ContentType]] 外键字段的名称。 默认为 <code>content_type</code></p></dd></dl>
[[#django.contrib.contenttypes.models.ContentType|<code>ContentType</code>]] foreign key
 
field on the model. Defaults to <code>content_type</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>ct_fk_field</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">ct_fk_field</span></span></dt>
<dd><p>The name of the integer field that represents the ID of the related
+
<dd><p>表示相关对象 ID 的整数字段的名称。 默认为 <code>object_id</code></p></dd></dl>
object. Defaults to <code>object_id</code>.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
; ''class'' <code>GenericTabularInline</code>
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">GenericTabularInline</span></span>
 
:  
 
:  
  
; ''class'' <code>GenericStackedInline</code>
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">GenericStackedInline</span></span>
: Subclasses of [[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|<code>GenericInlineModelAdmin</code>]] with stacked and tabular layouts, respectively.
+
: [[#django.contrib.contenttypes.admin.GenericInlineModelAdmin|GenericInlineModelAdmin]] 的子类,分别具有堆叠和表格布局。
  
  
第619行: 第436行:
  
 
</div>
 
</div>
 +
<div class="clearer">
  
[[Category:Django 3.0.x 中文文档]]
+
 
 +
 
 +
</div>
 +
 
 +
[[Category:Django 3.0.x 文档]]

2021年10月31日 (日) 04:09的最新版本

内容类型框架

Django 包含一个 contenttypes 应用程序,该应用程序可以跟踪安装在 Django 驱动的项目中的所有模型,提供用于处理模型的高级通用接口。

概览

contenttypes 应用程序的核心是 ContentType 模型,它位于 django.contrib.contenttypes.models.ContentTypeContentType 的实例表示并存储有关安装在项目中的模型的信息,并且每当安装新模型时都会自动创建 ContentType 的新实例。

ContentType 的实例具有返回它们所代表的模型类以及从这些模型中查询对象的方法。 ContentType 还有一个 自定义管理器 ,它添加了使用 ContentType 和获取特定模型的 ContentType 实例的方法。

您的模型与 ContentType 之间的关系还可用于启用您的模型之一的实例与您已安装的任何模型的实例之间的“通用”关系。


安装内容类型框架

contenttypes 框架包含在由 django-admin startproject 创建的默认 :setting:`INSTALLED_APPS` 列表中,但如果您已将其删除或手动设置 :setting: `INSTALLED_APPS` 列表,您可以通过将 'django.contrib.contenttypes' 添加到 :setting:`INSTALLED_APPS` 设置来启用它。

安装 contenttypes 框架通常是个好主意; 一些 Django 的其他捆绑应用程序需要它:

  • 管理应用程序使用它来记录通过管理界面添加或更改的每个对象的历史记录。
  • Django 的 身份验证框架 使用它来将用户权限绑定到特定模型。


ContentType型号

class ContentType

ContentType 的每个实例都有两个字段,它们共同唯一地描述了一个已安装的模型:

app_label

模型所属的应用程序的名称。 这取自模型的 app_label 属性,仅包含应用程序 Python 导入路径的 last 部分; 例如,django.contrib.contenttypes成为contenttypesapp_label

model

模型类的名称。

此外,以下属性可用:

name

内容类型的可读名称。 这取自模型的 verbose_name 属性。

让我们看一个例子,看看它是如何工作的。 如果您已经安装了 contenttypes 应用程序,然后将 站点应用程序 添加到您的 :setting:`INSTALLED_APPS` 设置并运行 manage.py migrate要安装它,模型 django.contrib.sites.models.Site 将安装到您的数据库中。 随之而来的是一个新的 ContentType 实例,其值如下:

  • app_label 将设置为 'sites'(Python 路径 django.contrib.sites 的最后一部分)。
  • 型号将设置为'site'


ContentType 实例上的方法

每个 ContentType 实例都有一些方法,允许您从 ContentType 实例获取它所代表的模型,或者从该模型中检索对象:

ContentType.get_object_for_this_type(**kwargs)
ContentType 表示的模型获取一组有效的 查找参数 ,并在该模型上执行 get() 查找 ,返回相应的对象。
ContentType.model_class()
返回由此 ContentType 实例表示的模型类。

例如,我们可以查找 User 模型的 ContentType

>>> 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() 一起实现了两个极其重要的用例:

  1. 使用这些方法,您可以编写对任何已安装模型执行查询的高级通用代码——而不是导入和使用单个特定模型类,您可以将 app_labelmodel 传递到ContentType 在运行时查找,然后使用模型类或从中检索对象。
  2. 您可以将另一个模型与 ContentType 相关联,作为将其实例绑定到特定模型类的一种方式,并使用这些方法来访问这些模型类。

Django 的一些捆绑应用程序使用了后一种技术。 比如Django的认证框架中的权限系统使用的是Permission模型,外键为ContentType; 这让 Permission 表示“可以添加博客条目”或“可以删除新闻报道”等概念。

ContentTypeManager

class ContentTypeManager

ContentType 还有一个自定义管理器,ContentTypeManager,它增加了以下方法:

clear_cache()

清除 ContentType 使用的内部缓存,以跟踪已为其创建 ContentType 实例的模型。 您可能永远不需要自己调用此方法; Django 会在需要时自动调用它。

get_for_id(id)

按 ID 查找 ContentType。 由于此方法使用与 get_for_model() 相同的共享缓存,因此优先使用此方法而不是通常的 ContentType.objects.get(pk=id)

get_for_model(model, for_concrete_model=True)

采用模型类或模型实例,并返回表示该模型的 ContentType 实例。 for_concrete_model=False 允许获取代理模型的 ContentType

get_for_models(*models, for_concrete_models=True)

采用可变数量的模型类,并返回一个将模型类映射到代表它们的 ContentType 实例的字典。 for_concrete_models=False 允许获取代理模型的 ContentType

get_by_natural_key(app_label, model)

返回由给定的应用程序标签和模型名称唯一标识的 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),它可以解决这个问题,并允许与任何模型建立关系:

class GenericForeignKey

设置 GenericForeignKey 分为三个部分:

  1. 给你的模型一个 ForeignKeyContentType。 该字段的常用名称是“content_type”。

  2. 为您的模型提供一个字段,该字段可以存储您将要关联的模型的主键值。 对于大多数模型,这意味着 PositiveIntegerField。 该字段的常用名称是“object_id”。

  3. 给你的模型一个 GenericForeignKey,并将上面描述的两个字段的名称传递给它。 如果这些字段被命名为“content_type”和“object_id”,你可以省略它——这些是 GenericForeignKey 将寻找的默认字段名称。

for_concrete_model

如果False,该字段将能够引用代理模型。 默认值为 True。 这将 for_concrete_model 参数映射到 get_for_model()

主键类型兼容性

“object_id”字段不必与相关模型上的主键字段的类型相同,但它们的主键值必须通过其 get_db_prep_value() 强制转换为与“object_id”字段相同的类型 方法。

例如,如果您想允许具有 IntegerFieldCharField 主键字段的模型的通用关系,您可以使用 CharField 作为“object_id”字段您的模型,因为整数可以通过 get_db_prep_value() 强制转换为字符串。

为了获得最大的灵活性,您可以使用没有定义最大长度的 TextField,但是这可能会导致显着的性能损失,具体取决于您的数据库后端。

对于哪种字段类型最合适,没有一刀切的解决方案。 您应该评估您希望指向的模型,并确定哪种解决方案对您的用例最有效。


序列化对 ContentType 对象的引用

如果您正在从实现通用关系的模型中序列化数据(例如,在生成 fixtures 时),您可能应该使用自然键来唯一标识相关的 ContentType 对象。 有关详细信息,请参阅 自然键dumpdata --natural-foreign


这将启用一个类似于用于普通 ForeignKey 的 API; 每个 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_typeobject_id 字段仍设置为其原始值,而 GenericForeignKey 返回 None

>>> guido.delete()
>>> t.content_object  # returns None

由于 GenericForeignKey 的实现方式,您不能通过数据库 API 直接将这些字段与过滤器(例如 filter()exclude())一起使用。 因为 GenericForeignKey 不是一个普通的字段对象,这些例子将 not 工作:

# This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)

同样,GenericForeignKeys 不会出现在 ModelForms 中。

反向泛型关系

class GenericRelation
;; related_query_name
默认情况下,相关对象与此对象之间的关系不存在。 设置 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')

这可以从 TaggedItem 启用对 Bookmark 的过滤、排序和其他查询操作:

>>> # 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_fkobject_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 信号提供替代行为。


通用关系和聚合

Django 的数据库聚合 API 使用 GenericRelation。 例如,您可以找出所有书签有多少个标签:

>>> Bookmark.objects.aggregate(Count('tags'))
{'tags__count': 3}

表单中的泛型关系

django.contrib.contenttypes.forms 模块提供:

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

使用 modelformset_factory() 返回 GenericInlineFormSet

如果 ct_fieldfk_field 与默认值不同,您必须分别提供 content_typeobject_id。 其他参数类似于 modelformset_factory()inlineformset_factory() 中记录的参数。

for_concrete_model 参数对应于 GenericForeignKey 上的 for_concrete_model 参数。

管理中的通用关系

django.contrib.contenttypes.admin 模块提供 GenericTabularInlineGenericStackedInlineGenericInlineModelAdmin 的子类)

这些类和函数允许在表单和管理中使用通用关系。 有关更多信息,请参阅 模型表单集管理 文档。

class GenericInlineModelAdmin

GenericInlineModelAdmin 类继承了 InlineModelAdmin 类的所有属性。 但是,它添加了一些自己的用于处理通用关系:

ct_field

模型上 ContentType 外键字段的名称。 默认为 content_type

ct_fk_field

表示相关对象 ID 的整数字段的名称。 默认为 object_id

class GenericTabularInline
class GenericStackedInline
GenericInlineModelAdmin 的子类,分别具有堆叠和表格布局。