“Django/docs/2.2.x/ref/contrib/postgres/fields”的版本间差异
(autoload) |
小 (Page commit) |
||
第1行: | 第1行: | ||
+ | {{DISPLAYTITLE:PostgreSQL 特定模型字段 — Django 文档}} | ||
<div id="postgresql-specific-model-fields" class="section"> | <div id="postgresql-specific-model-fields" class="section"> | ||
− | = PostgreSQL | + | = PostgreSQL 特有模型字段 = |
− | + | 所有这些字段都可以从 <code>django.contrib.postgres.fields</code> 模块获得。 | |
− | |||
<div id="indexing-these-fields" class="section"> | <div id="indexing-these-fields" class="section"> | ||
− | == | + | == 对这些字段进行索引 == |
− | [[../../../models/indexes#django.db.models| | + | [[../../../models/indexes#django.db.models|Index]] 和 [[../../../models/fields#django.db.models.Field|Field.db_index]] 都创建了 B 树索引,这在查询复杂数据类型时不是特别有用。 [[../indexes#django.contrib.postgres.indexes|GinIndex]] 和 [[../indexes#django.contrib.postgres.indexes|GistIndex]] 等索引更适合,尽管索引选择取决于您使用的查询。 通常,对于 [[#range-fields|范围字段]] 和 [[#django.contrib.postgres.fields.HStoreField|HStoreField]],GiST 可能是一个不错的选择,而 GIN 可能对 [[#django.contrib.postgres.fields.ArrayField|ArrayField]] 和 [[#django.contrib.postgres.fields.JSONField|JSONField]] 有帮助。 |
− | B | ||
− | |||
− | [[../indexes#django.contrib.postgres.indexes| | ||
− | |||
− | |||
− | [[#django.contrib.postgres.fields.HStoreField| | ||
− | [[#django.contrib.postgres.fields.JSONField| | ||
第23行: | 第16行: | ||
<div id="arrayfield" class="section"> | <div id="arrayfield" class="section"> | ||
− | == | + | == ArrayField == |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">ArrayField</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">base_field</span></span>'', ''<span class="n"><span class="pre">size</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>用于存储数据列表的字段。 大多数字段类型都可以使用,您只需将另一个字段实例作为 [[#django.contrib.postgres.fields.ArrayField.base_field|base_field]] 传递。 您还可以指定 [[#django.contrib.postgres.fields.ArrayField.size|大小]] 。 <code>ArrayField</code> 可以嵌套存储多维数组。</p> |
− | + | <p>如果您为该字段指定 [[../../../models/fields#django.db.models.Field|default]],请确保它是一个可调用对象,例如 <code>list</code>(对于一个空的默认值)或一个返回列表的可调用对象(例如一个函数)。 不正确地使用 <code>default=[]</code> 会创建一个可变默认值,该默认值在 <code>ArrayField</code> 的所有实例之间共享。</p> | |
− | |||
− | <p> | ||
− | |||
− | |||
− | |||
− | <code>ArrayField</code> | ||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">base_field</span></span></dt> |
− | <dd><p> | + | <dd><p>这是一个必要的参数。</p> |
− | <p> | + | <p>指定数组的基础数据类型和行为。 它应该是 [[../../../models/fields#django.db.models|Field]] 子类的一个实例。 例如,它可以是 [[../../../models/fields#django.db.models|IntegerField]] 或 [[../../../models/fields#django.db.models|CharField]]。 大多数字段类型都是允许的,但处理关系数据的字段类型除外([[../../../models/fields#django.db.models|ForeignKey]]、[[../../../models/fields#django.db.models|OneToOneField]] 和 [[../../../models/fields#django.db.models|ManyToManyField]])。</p> |
− | + | <p>可以嵌套数组字段 - 您可以将 <code>ArrayField</code> 的实例指定为 <code>base_field</code>。 例如:</p> | |
− | [[../../../models/fields#django.db.models| | ||
− | [[../../../models/fields#django.db.models| | ||
− | [[../../../models/fields#django.db.models| | ||
− | |||
− | |||
− | [[../../../models/fields#django.db.models| | ||
− | [[../../../models/fields#django.db.models| | ||
− | <p> | ||
− | <code>ArrayField</code> | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import ArrayField |
from django.db import models | from django.db import models | ||
第63行: | 第41行: | ||
), | ), | ||
size=8, | size=8, | ||
− | )</ | + | )</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>数据库和模型之间的值的转换、数据和配置的验证以及序列化都是委托给底层基础字段的。</p></dd></dl> |
− | |||
− | |||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">size</span></span></dt> |
− | <dd><p> | + | <dd><p>这是一个可选的参数。</p> |
− | <p> | + | <p>如果通过,数组将具有指定的最大大小。 这将传递给数据库,尽管 PostgreSQL 目前没有强制执行此限制。</p></dd></dl> |
− | |||
− | |||
</dd></dl> | </dd></dl> | ||
<div class="admonition note"> | <div class="admonition note"> | ||
− | + | 笔记 | |
− | + | 嵌套 <code>ArrayField</code> 时,无论是否使用 size 参数,PostgreSQL 都要求数组为矩形: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第91行: | 第64行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import ArrayField |
from django.db import models | from django.db import models | ||
第107行: | 第80行: | ||
[2, 3], | [2, 3], | ||
[2], | [2], | ||
− | ])</ | + | ])</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | + | 如果需要不规则的形状,那么底层字段应该可以为空,并且值用 <code>None</code> 填充。 | |
− | |||
第119行: | 第91行: | ||
<div id="querying-arrayfield" class="section"> | <div id="querying-arrayfield" class="section"> | ||
− | === | + | === 查询ArrayField === |
− | + | [[#django.contrib.postgres.fields.ArrayField|ArrayField]] 有许多自定义查找和转换。 我们将使用以下示例模型: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第128行: | 第99行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import ArrayField |
from django.db import models | from django.db import models | ||
第136行: | 第107行: | ||
def __str__(self): | def __str__(self): | ||
− | return self.name</ | + | return self.name</syntaxhighlight> |
</div> | </div> | ||
第143行: | 第114行: | ||
<div id="contains" class="section"> | <div id="contains" class="section"> | ||
− | + | ==== contains ==== | |
− | ==== | ||
− | + | [[#id1|:lookup:`contains`]] 查找在 [[#django.contrib.postgres.fields.ArrayField|ArrayField]] 上被覆盖。 返回的对象将是那些传递的值是数据子集的对象。 它使用 SQL 运算符 <code>@></code>。 例如: | |
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第154行: | 第122行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.create(name='Third post', tags=['tutorial', 'django']) | |
− | + | >>> Post.objects.filter(tags__contains=['thoughts']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]> | |
− | + | >>> Post.objects.filter(tags__contains=['django']) | |
− | + | <QuerySet [<Post: First post>, <Post: Third post>]> | |
− | + | >>> Post.objects.filter(tags__contains=['django', 'thoughts']) | |
− | + | <QuerySet [<Post: First post>]></syntaxhighlight> | |
</div> | </div> | ||
第174行: | 第142行: | ||
<div id="contained-by" class="section"> | <div id="contained-by" class="section"> | ||
− | + | ==== contained_by ==== | |
− | ==== | ||
− | + | 这是相反的 [[#id3|:lookup:`包含 `]] 查找 - 返回的对象将是那些数据是传递值的子集的对象。 它使用 SQL 运算符 <code><@</code>。 例如: | |
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第185行: | 第150行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.create(name='Third post', tags=['tutorial', 'django']) | |
− | + | >>> Post.objects.filter(tags__contained_by=['thoughts', 'django']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]> | |
− | + | >>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]></syntaxhighlight> | |
</div> | </div> | ||
第202行: | 第167行: | ||
<div id="overlap" class="section"> | <div id="overlap" class="section"> | ||
− | + | ==== overlap ==== | |
− | ==== | ||
− | + | 返回数据与传递的值共享任何结果的对象。 使用 SQL 运算符 <code>&&</code>。 例如: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第212行: | 第175行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.create(name='Third post', tags=['tutorial', 'django']) | |
− | + | >>> Post.objects.filter(tags__overlap=['thoughts']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]> | |
− | + | >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]></syntaxhighlight> | |
</div> | </div> | ||
第229行: | 第192行: | ||
<div id="len" class="section"> | <div id="len" class="section"> | ||
− | + | ==== len ==== | |
− | ==== | ||
− | + | 返回数组的长度。 之后可用的查找是可用于 [[../../../models/fields#django.db.models|IntegerField]] 的那些。 例如: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第239行: | 第200行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.filter(tags__len=1) | |
− | + | <QuerySet [<Post: Second post>]></syntaxhighlight> | |
</div> | </div> | ||
第252行: | 第213行: | ||
<div id="index-transforms" class="section"> | <div id="index-transforms" class="section"> | ||
− | + | ==== 索引转换 ==== | |
− | == | ||
− | + | 索引将索引转换为数组。 可以使用任何非负整数。 如果超过数组的 [[#django.contrib.postgres.fields.ArrayField.size|大小]] ,则没有错误。 转换后可用的查找来自 [[#django.contrib.postgres.fields.ArrayField.base_field|base_field]]。 例如: | |
− | |||
− | |||
− | [[#django.contrib.postgres.fields.ArrayField.base_field| | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第264行: | 第221行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.filter(tags__0='thoughts') | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]> | |
− | + | >>> Post.objects.filter(tags__1__iexact='Django') | |
− | + | <QuerySet [<Post: First post>]> | |
− | + | >>> Post.objects.filter(tags__276='javascript') | |
− | + | <QuerySet []></syntaxhighlight> | |
</div> | </div> | ||
第281行: | 第238行: | ||
<div class="admonition note"> | <div class="admonition note"> | ||
− | + | 笔记 | |
− | PostgreSQL | + | PostgreSQL 在编写原始 SQL 时对数组字段使用基于 1 的索引。 然而,这些索引和那些用于 [[#id5|:lookup:`切片 `]] 使用基于 0 的索引以与 Python 保持一致。 |
− | |||
− | |||
第293行: | 第248行: | ||
<div id="slice-transforms" class="section"> | <div id="slice-transforms" class="section"> | ||
− | + | ==== 切片转换 ==== | |
− | == | ||
− | + | 切片变换采用数组的切片。 可以使用任何两个非负整数,用单个下划线分隔。 转换后可用的查找不会改变。 例如: | |
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第304行: | 第256行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Post.objects.create(name='First post', tags=['thoughts', 'django']) |
− | + | >>> Post.objects.create(name='Second post', tags=['thoughts']) | |
− | + | >>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts']) | |
− | + | >>> Post.objects.filter(tags__0_1=['thoughts']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]> | |
− | + | >>> Post.objects.filter(tags__0_2__contains=['thoughts']) | |
− | + | <QuerySet [<Post: First post>, <Post: Second post>]></syntaxhighlight> | |
</div> | </div> | ||
第319行: | 第271行: | ||
<div class="admonition note"> | <div class="admonition note"> | ||
− | + | 笔记 | |
− | PostgreSQL | + | PostgreSQL 在编写原始 SQL 时对数组字段使用基于 1 的索引。 然而,这些切片和那些用于 [[#id7|:lookup:`索引 `]] 使用基于 0 的索引以与 Python 保持一致。 |
− | |||
− | |||
第329行: | 第279行: | ||
<div class="admonition-multidimensional-arrays-with-indexes-and-slices admonition"> | <div class="admonition-multidimensional-arrays-with-indexes-and-slices admonition"> | ||
− | + | 带索引和切片的多维数组 | |
− | + | 在多维数组上使用索引和切片时,PostgreSQL 有一些相当深奥的行为。 使用索引来深入到最终的底层数据总是有效的,但大多数其他切片在数据库级别的行为很奇怪,并且无法以逻辑一致的方式被 Django 支持。 | |
− | |||
− | |||
− | |||
− | |||
第347行: | 第293行: | ||
<div id="citext-fields" class="section"> | <div id="citext-fields" class="section"> | ||
− | == | + | == CIText 字段 == |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">CIText</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>创建由 [https://www.postgresql.org/docs/current/citext.html citext] 类型支持的不区分大小写的文本字段的 mixin。 在使用之前阅读 [https://www.postgresql.org/docs/current/citext.html#id-1.11.7.17.7 性能注意事项] 。</p> |
− | + | <p>要使用<code>citext</code>,在第一次<code>CreateModel</code>迁移操作之前,使用[[../operations#django.contrib.postgres.operations|CITextExtension]]操作在PostgreSQL中[[../operations#create-postgresql-extensions|设置citext扩展]]。</p> | |
− | <p> | + | <p>如果您使用 <code>CIText</code> 字段的 [[#django.contrib.postgres.fields.ArrayField|ArrayField]],则必须在 [[#id9|:setting:`INSTALLED_APPS`]] 中添加 <code>'django.contrib.postgres'</code>,否则字段值将显示为类似 <code>'{thoughts,django}'</code> 的字符串。</p> |
− | [[../operations#create-postgresql-extensions| | + | <p>提供了几个使用混入的字段:</p></dd></dl> |
− | |||
− | |||
− | |||
− | |||
− | |||
− | <p> | ||
− | ; ''class'' < | + | ; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">CICharField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span> |
: | : | ||
− | ; ''class'' < | + | ; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">CIEmailField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span> |
: | : | ||
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">CITextField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>这些字段分别是 [[../../../models/fields#django.db.models|CharField]]、[[../../../models/fields#django.db.models|EmailField]] 和 [[../../../models/fields#django.db.models|TextField]] 的子类。</p> |
− | [[../../../models/fields#django.db.models| | + | <p><code>max_length</code> 不会在数据库中强制执行,因为 <code>citext</code> 的行为类似于 PostgreSQL 的 <code>text</code> 类型。</p></dd></dl> |
− | [[../../../models/fields#django.db.models| | ||
− | <p><code>max_length</code> | ||
− | |||
第380行: | 第317行: | ||
<div id="hstorefield" class="section"> | <div id="hstorefield" class="section"> | ||
− | == | + | == HStoreField == |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">HStoreField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>用于存储键值对的字段。 使用的 Python 数据类型是 <code>dict</code>。 键必须是字符串,值可以是字符串或空值(Python 中的 <code>None</code>)。</p> |
− | <code>dict</code> | + | <p>要使用此字段,您需要:</p> |
− | |||
− | <p> | ||
<ol> | <ol> | ||
− | <li><p> | + | <li><p>在您的 [[#id11|:setting:`INSTALLED_APPS`]] 中添加 <code>'django.contrib.postgres'</code>。</p></li> |
− | <li><p>[[../operations#create-postgresql-extensions| | + | <li><p>[[../operations#create-postgresql-extensions|在PostgreSQL中设置hstore扩展]]。</p></li></ol> |
− | |||
− | <p> | + | <p>如果您跳过第一步,您将看到类似 <code>can't adapt type 'dict'</code> 的错误,如果您跳过第二步,则会看到 <code>type "hstore" does not exist</code> 之类的错误。</p></dd></dl> |
− | |||
<div class="admonition note"> | <div class="admonition note"> | ||
− | + | 笔记 | |
− | + | 有时,要求或限制对给定字段有效的键可能很有用。 这可以使用 [[../validators#django.contrib.postgres.validators|KeysValidator]] 来完成。 | |
− | |||
− | [[../validators#django.contrib.postgres.validators| | ||
第408行: | 第339行: | ||
<div id="querying-hstorefield" class="section"> | <div id="querying-hstorefield" class="section"> | ||
− | === | + | === 查询HStoreField === |
− | + | 除了按键查询的能力外,还有许多可用于 <code>HStoreField</code> 的自定义查找。 | |
− | |||
− | + | 我们将使用以下示例模型: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第419行: | 第349行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import HStoreField |
from django.db import models | from django.db import models | ||
第427行: | 第357行: | ||
def __str__(self): | def __str__(self): | ||
− | return self.name</ | + | return self.name</syntaxhighlight> |
</div> | </div> | ||
第434行: | 第364行: | ||
<div id="key-lookups" class="section"> | <div id="key-lookups" class="section"> | ||
− | + | ==== 键查找 ==== | |
− | == | ||
− | + | 要基于给定的键进行查询,您只需使用该键作为查找名称: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第443行: | 第372行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie'}) | |
− | + | >>> Dog.objects.filter(data__breed='collie') | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 您可以在键查找后链接其他查找: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第458行: | 第387行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.filter(data__breed__contains='l') |
− | + | <QuerySet [<Dog: Rufus>, <Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 如果您希望查询的键与另一个查找的名称发生冲突,您需要改用 [[#id13|:lookup:`hstorefield.contains`]] 查找。 | |
− | |||
<div class="admonition warning"> | <div class="admonition warning"> | ||
第471行: | 第399行: | ||
警告 | 警告 | ||
− | + | 由于任何字符串都可以是 hstore 值中的键,因此除下面列出的那些之外的任何查找都将被解释为键查找。 没有错误被提出。 输入错误时要格外小心,并始终检查您的查询是否按预期工作。 | |
− | |||
− | |||
− | |||
第480行: | 第405行: | ||
</div> | </div> | ||
− | <div id=" | + | <div id="id15" class="section"> |
− | + | ==== contains ==== | |
− | ==== | ||
− | + | [[#id16|:lookup:`contains`]] 查找在 [[#django.contrib.postgres.fields.HStoreField|HStoreField]] 上被覆盖。 返回的对象是那些给定的 <code>dict</code> 键值对都包含在字段中的对象。 它使用 SQL 运算符 <code>@></code>。 例如: | |
− | [[#django.contrib.postgres.fields.HStoreField| | ||
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第494行: | 第415行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.create(name='Fred', data={}) | |
− | + | >>> Dog.objects.filter(data__contains={'owner': 'Bob'}) | |
− | + | <QuerySet [<Dog: Rufus>, <Dog: Meg>]> | |
− | + | >>> Dog.objects.filter(data__contains={'breed': 'collie'}) | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第509行: | 第430行: | ||
</div> | </div> | ||
− | <div id=" | + | <div id="id18" class="section"> |
− | + | ==== contained_by ==== | |
− | ==== | ||
− | + | 这是相反的 [[#id19|:lookup:`包含 `]] 查找 - 返回的对象将是那些对象上的键值对是传递值中键值对的子集的对象。 它使用 SQL 运算符 <code><@</code>。 例如: | |
− | |||
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第523行: | 第440行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.create(name='Fred', data={}) | |
− | + | >>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | <QuerySet [<Dog: Meg>, <Dog: Fred>]> | |
− | + | >>> Dog.objects.filter(data__contained_by={'breed': 'collie'}) | |
− | + | <QuerySet [<Dog: Fred>]></syntaxhighlight> | |
</div> | </div> | ||
第540行: | 第457行: | ||
<div id="has-key" class="section"> | <div id="has-key" class="section"> | ||
− | + | ==== has_key ==== | |
− | ==== | ||
− | + | 返回给定键在数据中的对象。 使用 SQL 运算符 <code>?</code>。 例如: | |
− | <code>?</code> | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第550行: | 第465行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.filter(data__has_key='owner') | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第563行: | 第478行: | ||
<div id="has-any-keys" class="section"> | <div id="has-any-keys" class="section"> | ||
− | + | ==== has_any_keys ==== | |
− | ==== | ||
− | + | 返回任何给定键在数据中的对象。 使用 SQL 运算符 <code>?|</code>。 例如: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第573行: | 第486行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'owner': 'Bob'}) | |
− | + | >>> Dog.objects.create(name='Fred', data={}) | |
− | + | >>> Dog.objects.filter(data__has_any_keys=['owner', 'breed']) | |
− | + | <QuerySet [<Dog: Rufus>, <Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第587行: | 第500行: | ||
<div id="has-keys" class="section"> | <div id="has-keys" class="section"> | ||
− | + | ==== has_keys ==== | |
− | ==== | ||
− | + | 返回所有给定键都在数据中的对象。 使用 SQL 运算符 <code>?&</code>。 例如: | |
− | <code>?&</code> | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第597行: | 第508行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.filter(data__has_keys=['breed', 'owner']) | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第610行: | 第521行: | ||
<div id="keys" class="section"> | <div id="keys" class="section"> | ||
− | + | ==== keys ==== | |
− | ==== | ||
− | + | 返回键数组为给定值的对象。 请注意,不能保证顺序是可靠的,因此此转换主要用于与 [[#django.contrib.postgres.fields.ArrayField|ArrayField]] 上的查找结合使用。 使用 SQL 函数 <code>akeys()</code>。 例如: | |
− | |||
− | |||
− | [[#django.contrib.postgres.fields.ArrayField| | ||
− | <code>akeys()</code> | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第623行: | 第529行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'toy': 'bone'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.filter(data__keys__overlap=['breed', 'toy']) | |
− | + | <QuerySet [<Dog: Rufus>, <Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第636行: | 第542行: | ||
<div id="values" class="section"> | <div id="values" class="section"> | ||
− | + | ==== values ==== | |
− | ==== | ||
− | + | 返回值数组是给定值的对象。 请注意,不能保证顺序是可靠的,因此此转换主要用于与 [[#django.contrib.postgres.fields.ArrayField|ArrayField]] 上的查找结合使用。 使用 SQL 函数 <code>avalues()</code>。 例如: | |
− | |||
− | |||
− | [[#django.contrib.postgres.fields.ArrayField| | ||
− | <code>avalues()</code> | ||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第649行: | 第550行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'}) |
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'}) | |
− | + | >>> Dog.objects.filter(data__values__contains=['collie']) | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
第666行: | 第567行: | ||
<div id="jsonfield" class="section"> | <div id="jsonfield" class="section"> | ||
− | == | + | == JSONField == |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">JSONField</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">encoder</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>用于存储 JSON 编码数据的字段。 在 Python 中,数据以其 Python 原生格式表示:字典、列表、字符串、数字、布尔值和 <code>None</code>。</p> |
− | |||
− | |||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">encoder</span></span></dt> |
− | <dd><p> | + | <dd><p>一个可选的 JSON 编码类,用于序列化标准 JSON 序列化程序(<code>datetime</code>、<code>uuid</code> 等)不支持的数据类型。 例如,您可以使用 [[../../../../topics/serialization#django.core.serializers.json|DjangoJSONEncoder]] 类或任何其他 <code>json.JSONEncoder</code> 子类。</p> |
− | + | <p>从数据库中检索值时,它将采用自定义编码器选择的格式(通常是字符串),因此您需要采取额外的步骤将值转换回初始数据类型 ( [[../../../models/instances#django.db.models.Model|Model.from_db()]] 和 [[../../../models/fields#django.db.models.Field|Field.from_db_value()]] 是用于此目的的两个可能的钩子)。 您的反序列化可能需要考虑到您无法确定输入类型的事实。 例如,您冒着返回 <code>datetime</code> 的风险,该字符串实际上是一个恰好与为 <code>datetime</code> 选择的格式相同的字符串。</p></dd></dl> | |
− | |||
− | [[../../../../topics/serialization#django.core.serializers.json| | ||
− | |||
− | <p> | ||
− | |||
− | |||
− | ([[../../../models/instances#django.db.models.Model| | ||
− | [[../../../models/fields#django.db.models.Field| | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | <p> | + | <p>如果你给这个字段一个 [[../../../models/fields#django.db.models.Field|default]],确保它是一个可调用的,比如 <code>dict</code>(对于一个空的默认值)或一个返回一个字典的可调用的(比如一个函数)。 不正确地使用 <code>default={}</code> 会创建一个可变默认值,该默认值在 <code>JSONField</code> 的所有实例之间共享。</p></dd></dl> |
− | |||
− | |||
− | |||
− | <code>JSONField</code> | ||
<div class="admonition note"> | <div class="admonition note"> | ||
− | + | 笔记 | |
− | PostgreSQL | + | PostgreSQL 有两种基于 JSON 的原生数据类型:<code>json</code> 和 <code>jsonb</code>。 它们之间的主要区别在于它们的存储方式和查询方式。 PostgreSQL 的 <code>json</code> 字段存储为 JSON 的原始字符串表示形式,并且必须在基于键查询时即时解码。 <code>jsonb</code> 字段基于允许索引的 JSON 的实际结构进行存储。 权衡是写入 <code>jsonb</code> 字段的少量额外成本。 <code>JSONField</code> 使用 <code>jsonb</code>。 |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
第713行: | 第589行: | ||
<div id="querying-jsonfield" class="section"> | <div id="querying-jsonfield" class="section"> | ||
− | === | + | === 查询JSONField === |
− | + | 我们将使用以下示例模型: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第721行: | 第597行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import JSONField |
from django.db import models | from django.db import models | ||
第729行: | 第605行: | ||
def __str__(self): | def __str__(self): | ||
− | return self.name</ | + | return self.name</syntaxhighlight> |
</div> | </div> | ||
第736行: | 第612行: | ||
<div id="key-index-and-path-lookups" class="section"> | <div id="key-index-and-path-lookups" class="section"> | ||
− | + | ==== 键、索引和路径查找 ==== | |
− | == | ||
− | + | 要基于给定的字典键进行查询,只需使用该键作为查找名称: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第746行: | 第620行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Rufus', data={ |
... 'breed': 'labrador', | ... 'breed': 'labrador', | ||
... 'owner': { | ... 'owner': { | ||
第755行: | 第629行: | ||
... }, | ... }, | ||
... }) | ... }) | ||
− | + | >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None}) | |
− | + | >>> Dog.objects.filter(data__breed='collie') | |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 多个键可以链接在一起以形成路径查找: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第769行: | 第643行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.filter(data__owner__name='Bob') |
− | + | <QuerySet [<Dog: Rufus>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 如果键是整数,它将被解释为数组中的索引查找: | |
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第782行: | 第655行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy') |
− | + | <QuerySet [<Dog: Rufus>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 如果您希望查询的键与另一个查找的名称冲突,请改用 [[#id21|:lookup:`jsonfield.contains`]] 查找。 | |
− | |||
− | + | 如果仅使用一个键或索引,则使用 SQL 运算符 <code>-></code>。 如果使用多个运算符,则使用 <code>#></code> 运算符。 | |
− | |||
− | + | 要在 JSON 数据中查询 <code>null</code>,请使用 <code>None</code> 作为值: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第800行: | 第671行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.filter(data__owner=None) |
− | + | <QuerySet [<Dog: Meg>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 要查询丢失的键,请使用 <code>isnull</code> 查找: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第812行: | 第683行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Dog.objects.create(name='Shep', data={'breed': 'collie'}) |
− | + | >>> Dog.objects.filter(data__owner__isnull=True) | |
− | + | <QuerySet [<Dog: Shep>]></syntaxhighlight> | |
</div> | </div> | ||
第821行: | 第692行: | ||
<div class="versionchanged"> | <div class="versionchanged"> | ||
− | + | <span class="versionmodified changed"> 在 2.1 版更改: </span> 在旧版本中,使用 <code>None</code> 作为查找值匹配没有键的对象,而不是具有 <code>None</code> 键的对象价值。 | |
− | |||
− | |||
第831行: | 第700行: | ||
警告 | 警告 | ||
− | + | 由于任何字符串都可能是 JSON 对象中的键,因此除下面列出的那些之外的任何查找都将被解释为键查找。 没有错误被提出。 输入错误时要格外小心,并始终检查您的查询是否按预期工作。 | |
− | |||
− | |||
− | |||
第842行: | 第708行: | ||
<div id="containment-and-key-operations" class="section"> | <div id="containment-and-key-operations" class="section"> | ||
− | ==== | + | ==== 遏制和关键行动 ==== |
− | + | [[#django.contrib.postgres.fields.JSONField|JSONField]] 与 [[#django.contrib.postgres.fields.HStoreField|HStoreField]] 共享与容器和密钥相关的查找。 | |
− | |||
− | |||
− | * [[# | + | * [[#id23|:lookup:`包含 `]] (接受任何 JSON 而不仅仅是字符串字典) |
− | * [[# | + | * [[#id25|:lookup:`contained_by `]] (接受任何 JSON 而不仅仅是字符串字典) |
− | * [[# | + | * [[#id27|<span id="id28" class="problematic">:lookup:`has_key `</span>]] |
− | * [[# | + | * [[#id29|<span id="id30" class="problematic">:lookup:`has_any_keys `</span>]] |
− | * [[# | + | * [[#id31|<span id="id32" class="problematic">:lookup:`has_keys `</span>]] |
第862行: | 第726行: | ||
<div id="range-fields" class="section"> | <div id="range-fields" class="section"> | ||
− | <span id=" | + | <span id="id33"></span> |
− | == | + | == 范围字段 == |
− | + | 有五种范围字段类型,对应于 PostgreSQL 中内置的范围类型。 这些字段用于存储一系列值; 例如事件的开始和结束时间戳,或活动适合的年龄范围。 | |
− | PostgreSQL | ||
− | |||
− | |||
− | + | 在 Python 中,所有范围字段都转换为 <span class="xref std std-ref">psycopg2 范围对象 </span>,但如果不需要边界信息,也可以接受元组作为输入。 默认包含下限,排除上限; 即,<code>[)</code>。 | |
− | |||
− | |||
<div id="integerrangefield" class="section"> | <div id="integerrangefield" class="section"> | ||
− | === | + | === IntegerRangeField === |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">IntegerRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>存储一系列整数。 基于 [[../../../models/fields#django.db.models|IntegerField]]。 由数据库中的 <code>int4range</code> 和 Python 中的 <code>NumericRange</code> 表示。</p> |
− | [[../../../models/fields#django.db.models| | + | <p>无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即 <code>[)</code>。</p></dd></dl> |
− | |||
− | |||
− | <p> | ||
− | |||
− | |||
第892行: | 第746行: | ||
<div id="bigintegerrangefield" class="section"> | <div id="bigintegerrangefield" class="section"> | ||
− | === | + | === BigIntegerRangeField === |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">BigIntegerRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>存储一系列大整数。 基于 [[../../../models/fields#django.db.models|BigIntegerField]]。 由数据库中的 <code>int8range</code> 和 Python 中的 <code>NumericRange</code> 表示。</p> |
− | [[../../../models/fields#django.db.models| | + | <p>无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即 <code>[)</code>。</p></dd></dl> |
− | |||
− | |||
− | <p> | ||
− | |||
− | |||
第908行: | 第757行: | ||
<div id="decimalrangefield" class="section"> | <div id="decimalrangefield" class="section"> | ||
− | === | + | === DecimalRangeField === |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">DecimalRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
<dd><div class="versionadded"> | <dd><div class="versionadded"> | ||
− | + | <p><span class="versionmodified added">2.2 版中的新功能。</span></p> | |
</div> | </div> | ||
− | <p> | + | <p>存储一系列浮点值。 基于 [[../../../models/fields#django.db.models|DecimalField]]。 由数据库中的 <code>numrange</code> 和 Python 中的 <code>NumericRange</code> 表示。</p></dd></dl> |
− | [[../../../models/fields#django.db.models| | ||
− | |||
− | |||
第926行: | 第772行: | ||
<div id="floatrangefield" class="section"> | <div id="floatrangefield" class="section"> | ||
− | === | + | === FloatRangeField === |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">FloatRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>存储一系列浮点值。 基于 [[../../../models/fields#django.db.models|FloatField]]。 由数据库中的 <code>numrange</code> 和 Python 中的 <code>NumericRange</code> 表示。</p> |
− | [[../../../models/fields#django.db.models| | ||
− | |||
<div class="deprecated"> | <div class="deprecated"> | ||
− | <p><span class="versionmodified deprecated">2.2 | + | <p><span class="versionmodified deprecated"> 自 2.2 版起已弃用:</span> 改用 [[#django.contrib.postgres.fields.DecimalRangeField|DecimalRangeField]]。</p> |
</div></dd></dl> | </div></dd></dl> | ||
第943行: | 第787行: | ||
<div id="datetimerangefield" class="section"> | <div id="datetimerangefield" class="section"> | ||
− | === | + | === DateTimeRangeField === |
− | ; ''class'' < | + | ; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">DateTimeRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span> |
− | : | + | : 存储一系列时间戳。 基于 [[../../../models/fields#django.db.models|DateTimeField]]。 由数据库中的 <code>tstzrange</code> 和 Python 中的 <code>DateTimeTZRange</code> 表示。 |
第952行: | 第796行: | ||
<div id="daterangefield" class="section"> | <div id="daterangefield" class="section"> | ||
− | === | + | === DateRangeField === |
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">DateRangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>存储一系列日期。 基于 [[../../../models/fields#django.db.models|DateField]]。 由数据库中的 <code>daterange</code> 和 Python 中的 <code>DateRange</code> 表示。</p> |
− | [[../../../models/fields#django.db.models| | + | <p>无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即 <code>[)</code>。</p></dd></dl> |
− | |||
− | <p> | ||
− | |||
− | |||
第967行: | 第807行: | ||
<div id="querying-range-fields" class="section"> | <div id="querying-range-fields" class="section"> | ||
− | === | + | === 查询范围字段 === |
− | + | 范围字段有许多自定义查找和转换。 它们可用于上述所有字段,但我们将使用以下示例模型: | |
− | |||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第977行: | 第815行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">from django.contrib.postgres.fields import IntegerRangeField |
from django.db import models | from django.db import models | ||
第986行: | 第824行: | ||
def __str__(self): | def __str__(self): | ||
− | return self.name</ | + | return self.name</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | + | 我们还将使用以下示例对象: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第997行: | 第835行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> import datetime |
− | + | >>> from django.utils import timezone | |
− | + | >>> now = timezone.now() | |
− | + | >>> Event.objects.create(name='Soft play', ages=(0, 10), start=now) | |
− | + | >>> Event.objects.create(name='Pub trip', ages=(21, None), start=now - datetime.timedelta(days=1))</syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | 和 <code>NumericRange</code>: | |
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,012行: | 第850行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> from psycopg2.extras import NumericRange</syntaxhighlight> |
</div> | </div> | ||
第1,019行: | 第857行: | ||
<div id="containment-functions" class="section"> | <div id="containment-functions" class="section"> | ||
− | ==== | + | ==== 包含函数 ==== |
− | + | 与其他 PostgreSQL 字段一样,有三个标准的包含运算符:<code>contains</code>、<code>contained_by</code> 和 <code>overlap</code>,使用 SQL 运算符 <code>@></code>、<code><@</code> ] 和 <code>&&</code>。 | |
− | |||
− | |||
− | <div id=" | + | <div id="id34" class="section"> |
− | + | ===== contains ===== | |
− | ===== | ||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,034行: | 第869行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__contains=NumericRange(4, 5)) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,042行: | 第877行: | ||
</div> | </div> | ||
− | <div id=" | + | <div id="id35" class="section"> |
− | + | ===== contained_by ===== | |
− | ===== | ||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,051行: | 第885行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15)) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
</div> | </div> | ||
− | + | <code>contained_by</code> 查找也可用于非范围字段类型:[[../../../models/fields#django.db.models|IntegerField]]、[[../../../models/fields#django.db.models|BigIntegerField]]、[[../../../models/fields#django.db.models|FloatField]]、[[../../../models/fields#django.db.models|DateField]] , 和 [[../../../models/fields#django.db.models|DateTimeField]]。 例如: | |
− | [[../../../models/fields#django.db.models| | ||
− | [[../../../models/fields#django.db.models| | ||
− | [[../../../models/fields#django.db.models| | ||
− | |||
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第1,067行: | 第897行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> from psycopg2.extras import DateTimeTZRange |
− | + | >>> Event.objects.filter(start__contained_by=DateTimeTZRange( | |
... timezone.now() - datetime.timedelta(hours=1), | ... timezone.now() - datetime.timedelta(hours=1), | ||
... timezone.now() + datetime.timedelta(hours=1), | ... timezone.now() + datetime.timedelta(hours=1), | ||
... ) | ... ) | ||
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,079行: | 第909行: | ||
</div> | </div> | ||
− | <div id=" | + | <div id="id36" class="section"> |
− | + | ===== overlap ===== | |
− | ===== | ||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,088行: | 第917行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__overlap=NumericRange(8, 12)) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,100行: | 第929行: | ||
<div id="comparison-functions" class="section"> | <div id="comparison-functions" class="section"> | ||
− | ==== | + | ==== 比较函数 ==== |
− | + | 范围字段支持标准查找: [[#id37|:lookup:`lt`]]、[[#id39|:lookup:`gt`]]、[[#id41|:lookup:`lte`]] 和 [[#id43|:查找:`gte`]]。 这些不是特别有用 - 它们首先比较下限,然后仅在必要时比较上限。 这也是用于按范围字段排序的策略。 最好使用特定的范围比较运算符。 | |
− | [[ | ||
− | |||
− | |||
− | |||
<div id="fully-lt" class="section"> | <div id="fully-lt" class="section"> | ||
− | + | ===== fully_lt ===== | |
− | ===== | ||
− | + | 返回的范围严格小于传递的范围。 换句话说,返回范围内的所有点都小于传递范围内的所有点。 | |
− | |||
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,121行: | 第943行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15)) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,131行: | 第953行: | ||
<div id="fully-gt" class="section"> | <div id="fully-gt" class="section"> | ||
− | + | ===== fully_gt ===== | |
− | ===== | ||
− | + | 返回的范围严格大于传递的范围。 换句话说,返回范围内的所有点都大于传递范围内的所有点。 | |
− | |||
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,142行: | 第961行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15)) |
− | + | <QuerySet [<Event: Pub trip>]></syntaxhighlight> | |
</div> | </div> | ||
第1,152行: | 第971行: | ||
<div id="not-lt" class="section"> | <div id="not-lt" class="section"> | ||
− | + | ===== not_lt ===== | |
− | ===== | ||
− | + | 返回的范围不包含任何小于传入范围的点,即返回范围的下界至少是传入范围的下界。 | |
− | |||
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,163行: | 第979行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__not_lt=NumericRange(0, 15)) |
− | + | <QuerySet [<Event: Soft play>, <Event: Pub trip>]></syntaxhighlight> | |
</div> | </div> | ||
第1,173行: | 第989行: | ||
<div id="not-gt" class="section"> | <div id="not-gt" class="section"> | ||
− | + | ===== not_gt ===== | |
− | ===== | ||
− | + | 返回的范围不包含任何大于传入范围的点,也就是说,返回的范围的上界最多就是传入范围的上界。 | |
− | |||
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,184行: | 第997行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__not_gt=NumericRange(3, 10)) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,194行: | 第1,007行: | ||
<div id="adjacent-to" class="section"> | <div id="adjacent-to" class="section"> | ||
− | + | ===== adjacent_to ===== | |
− | ===== | ||
− | + | 返回的范围与传入的范围共享一个边界。 | |
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,203行: | 第1,015行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21)) |
− | + | <QuerySet [<Event: Soft play>, <Event: Pub trip>]></syntaxhighlight> | |
</div> | </div> | ||
第1,215行: | 第1,027行: | ||
<div id="querying-using-the-bounds" class="section"> | <div id="querying-using-the-bounds" class="section"> | ||
− | ==== | + | ==== 使用边界进行查询 ==== |
− | + | 有三种转换可用于查询。 您可以提取下限或上限,或根据空值进行查询。 | |
− | |||
<div id="startswith" class="section"> | <div id="startswith" class="section"> | ||
− | + | ===== startswith ===== | |
− | ===== | ||
− | + | 返回的对象具有给定的下限。 可以链接到基本字段的有效查找。 | |
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,232行: | 第1,041行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__startswith=21) |
− | + | <QuerySet [<Event: Pub trip>]></syntaxhighlight> | |
</div> | </div> | ||
第1,242行: | 第1,051行: | ||
<div id="endswith" class="section"> | <div id="endswith" class="section"> | ||
− | + | ===== endswith ===== | |
− | ===== | ||
− | + | 返回的对象具有给定的上限。 可以链接到基本字段的有效查找。 | |
− | |||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,252行: | 第1,059行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__endswith=10) |
− | + | <QuerySet [<Event: Soft play>]></syntaxhighlight> | |
</div> | </div> | ||
第1,262行: | 第1,069行: | ||
<div id="isempty" class="section"> | <div id="isempty" class="section"> | ||
− | + | ===== isempty ===== | |
− | ===== | ||
− | + | 返回的对象是空范围。 可以链接到 [[../../../models/fields#django.db.models|BooleanField]] 的有效查找。 | |
− | [[../../../models/fields#django.db.models| | ||
<div class="doctest highlight-default notranslate"> | <div class="doctest highlight-default notranslate"> | ||
第1,272行: | 第1,077行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">>>> Event.objects.filter(ages__isempty=True) |
− | + | <QuerySet []></syntaxhighlight> | |
</div> | </div> | ||
第1,286行: | 第1,091行: | ||
<div id="defining-your-own-range-types" class="section"> | <div id="defining-your-own-range-types" class="section"> | ||
− | === | + | === 定义自己的范围类型 === |
− | PostgreSQL | + | PostgreSQL 允许定义自定义范围类型。 Django 的模型和表单字段实现使用下面的基类,并且 psycopg2 提供了 <code>register_range()</code> 以允许使用自定义范围类型。 |
− | |||
− | <code>register_range()</code> | ||
− | |||
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">RangeField</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">options</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>模型范围字段的基类。</p> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">base_field</span></span></dt> |
− | <dd><p> | + | <dd><p>要使用的模型字段类。</p></dd></dl> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">range_type</span></span></dt> |
− | <dd><p> | + | <dd><p>要使用的 psycopg2 范围类型。</p></dd></dl> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">form_field</span></span></dt> |
− | <dd><p> | + | <dd><p>要使用的表单字段类。 应该是 [[#django.contrib.postgres.fields.django.contrib.postgres.forms.BaseRangeField|django.contrib.postgres.forms.BaseRangeField]] 的子类。</p></dd></dl> |
− | [[#django.contrib.postgres.fields.django.contrib.postgres.forms.BaseRangeField| | ||
</dd></dl> | </dd></dl> | ||
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-prename descclassname"><span class="pre">django.contrib.postgres.forms.</span></span><span class="sig-name descname"><span class="pre">BaseRangeField</span></span></dt> |
− | <dd><p> | + | <dd><p>表范围字段的基类。</p> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">base_field</span></span></dt> |
− | <dd><p> | + | <dd><p>要使用的表字段。</p></dd></dl> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">range_type</span></span></dt> |
− | <dd><p> | + | <dd><p>要使用的 psycopg2 范围类型。</p></dd></dl> |
</dd></dl> | </dd></dl> | ||
第1,326行: | 第1,127行: | ||
</div> | </div> | ||
+ | |||
+ | </div> | ||
+ | <div class="clearer"> | ||
+ | |||
+ | |||
</div> | </div> | ||
− | [[Category:Django 2.2.x | + | [[Category:Django 2.2.x 文档]] |
2021年10月31日 (日) 04:05的最新版本
PostgreSQL 特有模型字段
所有这些字段都可以从 django.contrib.postgres.fields
模块获得。
对这些字段进行索引
Index 和 Field.db_index 都创建了 B 树索引,这在查询复杂数据类型时不是特别有用。 GinIndex 和 GistIndex 等索引更适合,尽管索引选择取决于您使用的查询。 通常,对于 范围字段 和 HStoreField,GiST 可能是一个不错的选择,而 GIN 可能对 ArrayField 和 JSONField 有帮助。
ArrayField
- class ArrayField(base_field, size=None, **options)
用于存储数据列表的字段。 大多数字段类型都可以使用,您只需将另一个字段实例作为 base_field 传递。 您还可以指定 大小 。
ArrayField
可以嵌套存储多维数组。如果您为该字段指定 default,请确保它是一个可调用对象,例如
list
(对于一个空的默认值)或一个返回列表的可调用对象(例如一个函数)。 不正确地使用default=[]
会创建一个可变默认值,该默认值在ArrayField
的所有实例之间共享。- base_field
这是一个必要的参数。
指定数组的基础数据类型和行为。 它应该是 Field 子类的一个实例。 例如,它可以是 IntegerField 或 CharField。 大多数字段类型都是允许的,但处理关系数据的字段类型除外(ForeignKey、OneToOneField 和 ManyToManyField)。
可以嵌套数组字段 - 您可以将
ArrayField
的实例指定为base_field
。 例如:from django.contrib.postgres.fields import ArrayField from django.db import models class ChessBoard(models.Model): board = ArrayField( ArrayField( models.CharField(max_length=10, blank=True), size=8, ), size=8, )
数据库和模型之间的值的转换、数据和配置的验证以及序列化都是委托给底层基础字段的。
- size
这是一个可选的参数。
如果通过,数组将具有指定的最大大小。 这将传递给数据库,尽管 PostgreSQL 目前没有强制执行此限制。
笔记
嵌套 ArrayField
时,无论是否使用 size 参数,PostgreSQL 都要求数组为矩形:
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Board(models.Model):
pieces = ArrayField(ArrayField(models.IntegerField()))
# Valid
Board(pieces=[
[2, 3],
[2, 1],
])
# Not valid
Board(pieces=[
[2, 3],
[2],
])
如果需要不规则的形状,那么底层字段应该可以为空,并且值用 None
填充。
查询ArrayField
ArrayField 有许多自定义查找和转换。 我们将使用以下示例模型:
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Post(models.Model):
name = models.CharField(max_length=200)
tags = ArrayField(models.CharField(max_length=200), blank=True)
def __str__(self):
return self.name
contains
:lookup:`contains` 查找在 ArrayField 上被覆盖。 返回的对象将是那些传递的值是数据子集的对象。 它使用 SQL 运算符 @>
。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
>>> Post.objects.filter(tags__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__contains=['django'])
<QuerySet [<Post: First post>, <Post: Third post>]>
>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
<QuerySet [<Post: First post>]>
contained_by
这是相反的 :lookup:`包含 ` 查找 - 返回的对象将是那些数据是传递值的子集的对象。 它使用 SQL 运算符 <@
。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
>>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
overlap
返回数据与传递的值共享任何结果的对象。 使用 SQL 运算符 &&
。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
>>> Post.objects.filter(tags__overlap=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
len
返回数组的长度。 之后可用的查找是可用于 IntegerField 的那些。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.filter(tags__len=1)
<QuerySet [<Post: Second post>]>
索引转换
索引将索引转换为数组。 可以使用任何非负整数。 如果超过数组的 大小 ,则没有错误。 转换后可用的查找来自 base_field。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.filter(tags__0='thoughts')
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__1__iexact='Django')
<QuerySet [<Post: First post>]>
>>> Post.objects.filter(tags__276='javascript')
<QuerySet []>
切片转换
切片变换采用数组的切片。 可以使用任何两个非负整数,用单个下划线分隔。 转换后可用的查找不会改变。 例如:
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])
>>> Post.objects.filter(tags__0_1=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__0_2__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>
带索引和切片的多维数组
在多维数组上使用索引和切片时,PostgreSQL 有一些相当深奥的行为。 使用索引来深入到最终的底层数据总是有效的,但大多数其他切片在数据库级别的行为很奇怪,并且无法以逻辑一致的方式被 Django 支持。
CIText 字段
- class CIText(**options)
创建由 citext 类型支持的不区分大小写的文本字段的 mixin。 在使用之前阅读 性能注意事项 。
要使用
citext
,在第一次CreateModel
迁移操作之前,使用CITextExtension操作在PostgreSQL中设置citext扩展。如果您使用
CIText
字段的 ArrayField,则必须在 :setting:`INSTALLED_APPS` 中添加'django.contrib.postgres'
,否则字段值将显示为类似'{thoughts,django}'
的字符串。提供了几个使用混入的字段:
- class CICharField(**options)
- class CIEmailField(**options)
- class CITextField(**options)
这些字段分别是 CharField、EmailField 和 TextField 的子类。
max_length
不会在数据库中强制执行,因为citext
的行为类似于 PostgreSQL 的text
类型。
HStoreField
- class HStoreField(**options)
用于存储键值对的字段。 使用的 Python 数据类型是
dict
。 键必须是字符串,值可以是字符串或空值(Python 中的None
)。要使用此字段,您需要:
在您的 :setting:`INSTALLED_APPS` 中添加
'django.contrib.postgres'
。
如果您跳过第一步,您将看到类似
can't adapt type 'dict'
的错误,如果您跳过第二步,则会看到type "hstore" does not exist
之类的错误。
查询HStoreField
除了按键查询的能力外,还有许多可用于 HStoreField
的自定义查找。
我们将使用以下示例模型:
from django.contrib.postgres.fields import HStoreField
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=200)
data = HStoreField()
def __str__(self):
return self.name
键查找
要基于给定的键进行查询,您只需使用该键作为查找名称:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
您可以在键查找后链接其他查找:
>>> Dog.objects.filter(data__breed__contains='l')
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
如果您希望查询的键与另一个查找的名称发生冲突,您需要改用 :lookup:`hstorefield.contains` 查找。
警告
由于任何字符串都可以是 hstore 值中的键,因此除下面列出的那些之外的任何查找都将被解释为键查找。 没有错误被提出。 输入错误时要格外小心,并始终检查您的查询是否按预期工作。
contains
:lookup:`contains` 查找在 HStoreField 上被覆盖。 返回的对象是那些给定的 dict
键值对都包含在字段中的对象。 它使用 SQL 运算符 @>
。 例如:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})
>>> Dog.objects.filter(data__contains={'owner': 'Bob'})
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
>>> Dog.objects.filter(data__contains={'breed': 'collie'})
<QuerySet [<Dog: Meg>]>
contained_by
这是相反的 :lookup:`包含 ` 查找 - 返回的对象将是那些对象上的键值对是传递值中键值对的子集的对象。 它使用 SQL 运算符 <@
。 例如:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})
>>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
<QuerySet [<Dog: Meg>, <Dog: Fred>]>
>>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
<QuerySet [<Dog: Fred>]>
has_key
返回给定键在数据中的对象。 使用 SQL 运算符 ?
。 例如:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.filter(data__has_key='owner')
<QuerySet [<Dog: Meg>]>
has_any_keys
返回任何给定键在数据中的对象。 使用 SQL 运算符 ?|
。 例如:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})
>>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
has_keys
返回所有给定键都在数据中的对象。 使用 SQL 运算符 ?&
。 例如:
>>> Dog.objects.create(name='Rufus', data={})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
<QuerySet [<Dog: Meg>]>
keys
返回键数组为给定值的对象。 请注意,不能保证顺序是可靠的,因此此转换主要用于与 ArrayField 上的查找结合使用。 使用 SQL 函数 akeys()
。 例如:
>>> Dog.objects.create(name='Rufus', data={'toy': 'bone'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.filter(data__keys__overlap=['breed', 'toy'])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
values
返回值数组是给定值的对象。 请注意,不能保证顺序是可靠的,因此此转换主要用于与 ArrayField 上的查找结合使用。 使用 SQL 函数 avalues()
。 例如:
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.filter(data__values__contains=['collie'])
<QuerySet [<Dog: Meg>]>
JSONField
- class JSONField(encoder=None, **options)
用于存储 JSON 编码数据的字段。 在 Python 中,数据以其 Python 原生格式表示:字典、列表、字符串、数字、布尔值和
None
。- encoder
一个可选的 JSON 编码类,用于序列化标准 JSON 序列化程序(
datetime
、uuid
等)不支持的数据类型。 例如,您可以使用 DjangoJSONEncoder 类或任何其他json.JSONEncoder
子类。从数据库中检索值时,它将采用自定义编码器选择的格式(通常是字符串),因此您需要采取额外的步骤将值转换回初始数据类型 ( Model.from_db() 和 Field.from_db_value() 是用于此目的的两个可能的钩子)。 您的反序列化可能需要考虑到您无法确定输入类型的事实。 例如,您冒着返回
datetime
的风险,该字符串实际上是一个恰好与为datetime
选择的格式相同的字符串。
如果你给这个字段一个 default,确保它是一个可调用的,比如
dict
(对于一个空的默认值)或一个返回一个字典的可调用的(比如一个函数)。 不正确地使用default={}
会创建一个可变默认值,该默认值在JSONField
的所有实例之间共享。
笔记
PostgreSQL 有两种基于 JSON 的原生数据类型:json
和 jsonb
。 它们之间的主要区别在于它们的存储方式和查询方式。 PostgreSQL 的 json
字段存储为 JSON 的原始字符串表示形式,并且必须在基于键查询时即时解码。 jsonb
字段基于允许索引的 JSON 的实际结构进行存储。 权衡是写入 jsonb
字段的少量额外成本。 JSONField
使用 jsonb
。
查询JSONField
我们将使用以下示例模型:
from django.contrib.postgres.fields import JSONField
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=200)
data = JSONField()
def __str__(self):
return self.name
键、索引和路径查找
要基于给定的字典键进行查询,只需使用该键作为查找名称:
>>> Dog.objects.create(name='Rufus', data={
... 'breed': 'labrador',
... 'owner': {
... 'name': 'Bob',
... 'other_pets': [{
... 'name': 'Fishy',
... }],
... },
... })
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
多个键可以链接在一起以形成路径查找:
>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>
如果键是整数,它将被解释为数组中的索引查找:
>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>
如果您希望查询的键与另一个查找的名称冲突,请改用 :lookup:`jsonfield.contains` 查找。
如果仅使用一个键或索引,则使用 SQL 运算符 ->
。 如果使用多个运算符,则使用 #>
运算符。
要在 JSON 数据中查询 null
,请使用 None
作为值:
>>> Dog.objects.filter(data__owner=None)
<QuerySet [<Dog: Meg>]>
要查询丢失的键,请使用 isnull
查找:
>>> Dog.objects.create(name='Shep', data={'breed': 'collie'})
>>> Dog.objects.filter(data__owner__isnull=True)
<QuerySet [<Dog: Shep>]>
在 2.1 版更改: 在旧版本中,使用 None
作为查找值匹配没有键的对象,而不是具有 None
键的对象价值。
警告
由于任何字符串都可能是 JSON 对象中的键,因此除下面列出的那些之外的任何查找都将被解释为键查找。 没有错误被提出。 输入错误时要格外小心,并始终检查您的查询是否按预期工作。
遏制和关键行动
JSONField 与 HStoreField 共享与容器和密钥相关的查找。
- :lookup:`包含 ` (接受任何 JSON 而不仅仅是字符串字典)
- :lookup:`contained_by ` (接受任何 JSON 而不仅仅是字符串字典)
- :lookup:`has_key `
- :lookup:`has_any_keys `
- :lookup:`has_keys `
范围字段
有五种范围字段类型,对应于 PostgreSQL 中内置的范围类型。 这些字段用于存储一系列值; 例如事件的开始和结束时间戳,或活动适合的年龄范围。
在 Python 中,所有范围字段都转换为 psycopg2 范围对象 ,但如果不需要边界信息,也可以接受元组作为输入。 默认包含下限,排除上限; 即,[)
。
IntegerRangeField
- class IntegerRangeField(**options)
存储一系列整数。 基于 IntegerField。 由数据库中的
int4range
和 Python 中的NumericRange
表示。无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即
[)
。
BigIntegerRangeField
- class BigIntegerRangeField(**options)
存储一系列大整数。 基于 BigIntegerField。 由数据库中的
int8range
和 Python 中的NumericRange
表示。无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即
[)
。
DecimalRangeField
- class DecimalRangeField(**options)
2.2 版中的新功能。
存储一系列浮点值。 基于 DecimalField。 由数据库中的
numrange
和 Python 中的NumericRange
表示。
FloatRangeField
- class FloatRangeField(**options)
存储一系列浮点值。 基于 FloatField。 由数据库中的
numrange
和 Python 中的NumericRange
表示。自 2.2 版起已弃用: 改用 DecimalRangeField。
DateTimeRangeField
- class DateTimeRangeField(**options)
- 存储一系列时间戳。 基于 DateTimeField。 由数据库中的
tstzrange
和 Python 中的DateTimeTZRange
表示。
DateRangeField
- class DateRangeField(**options)
存储一系列日期。 基于 DateField。 由数据库中的
daterange
和 Python 中的DateRange
表示。无论保存数据时指定的边界如何,PostgreSQL 总是以规范的形式返回一个范围,该范围包括下限和不包括上限; 即
[)
。
查询范围字段
范围字段有许多自定义查找和转换。 它们可用于上述所有字段,但我们将使用以下示例模型:
from django.contrib.postgres.fields import IntegerRangeField
from django.db import models
class Event(models.Model):
name = models.CharField(max_length=200)
ages = IntegerRangeField()
start = models.DateTimeField()
def __str__(self):
return self.name
我们还将使用以下示例对象:
>>> import datetime
>>> from django.utils import timezone
>>> now = timezone.now()
>>> Event.objects.create(name='Soft play', ages=(0, 10), start=now)
>>> Event.objects.create(name='Pub trip', ages=(21, None), start=now - datetime.timedelta(days=1))
和 NumericRange
:
>>> from psycopg2.extras import NumericRange
包含函数
与其他 PostgreSQL 字段一样,有三个标准的包含运算符:contains
、contained_by
和 overlap
,使用 SQL 运算符 @>
、<@
] 和 &&
。
contains
>>> Event.objects.filter(ages__contains=NumericRange(4, 5))
<QuerySet [<Event: Soft play>]>
contained_by
>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
<QuerySet [<Event: Soft play>]>
contained_by
查找也可用于非范围字段类型:IntegerField、BigIntegerField、FloatField、DateField , 和 DateTimeField。 例如:
>>> from psycopg2.extras import DateTimeTZRange
>>> Event.objects.filter(start__contained_by=DateTimeTZRange(
... timezone.now() - datetime.timedelta(hours=1),
... timezone.now() + datetime.timedelta(hours=1),
... )
<QuerySet [<Event: Soft play>]>
overlap
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
<QuerySet [<Event: Soft play>]>
比较函数
范围字段支持标准查找: :lookup:`lt`、:lookup:`gt`、:lookup:`lte` 和 :查找:`gte`。 这些不是特别有用 - 它们首先比较下限,然后仅在必要时比较上限。 这也是用于按范围字段排序的策略。 最好使用特定的范围比较运算符。
fully_lt
返回的范围严格小于传递的范围。 换句话说,返回范围内的所有点都小于传递范围内的所有点。
>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
<QuerySet [<Event: Soft play>]>
fully_gt
返回的范围严格大于传递的范围。 换句话说,返回范围内的所有点都大于传递范围内的所有点。
>>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
<QuerySet [<Event: Pub trip>]>
not_lt
返回的范围不包含任何小于传入范围的点,即返回范围的下界至少是传入范围的下界。
>>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
not_gt
返回的范围不包含任何大于传入范围的点,也就是说,返回的范围的上界最多就是传入范围的上界。
>>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
<QuerySet [<Event: Soft play>]>
adjacent_to
返回的范围与传入的范围共享一个边界。
>>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
使用边界进行查询
有三种转换可用于查询。 您可以提取下限或上限,或根据空值进行查询。
startswith
返回的对象具有给定的下限。 可以链接到基本字段的有效查找。
>>> Event.objects.filter(ages__startswith=21)
<QuerySet [<Event: Pub trip>]>
endswith
返回的对象具有给定的上限。 可以链接到基本字段的有效查找。
>>> Event.objects.filter(ages__endswith=10)
<QuerySet [<Event: Soft play>]>
isempty
返回的对象是空范围。 可以链接到 BooleanField 的有效查找。
>>> Event.objects.filter(ages__isempty=True)
<QuerySet []>
定义自己的范围类型
PostgreSQL 允许定义自定义范围类型。 Django 的模型和表单字段实现使用下面的基类,并且 psycopg2 提供了 register_range()
以允许使用自定义范围类型。
- class RangeField(**options)
模型范围字段的基类。
- base_field
要使用的模型字段类。
- range_type
要使用的 psycopg2 范围类型。
- form_field
要使用的表单字段类。 应该是 django.contrib.postgres.forms.BaseRangeField 的子类。
- class django.contrib.postgres.forms.BaseRangeField
表范围字段的基类。
- base_field
要使用的表字段。
- range_type
要使用的 psycopg2 范围类型。