PostgreSQL 特定模型字段

所有这些字段都可以在 django.contrib.postgres.fields 模块中找到。

索引这些字段

IndexField.db_index 都创建了一个 B 树索引,这在查询复杂数据类型时并不是特别有用。诸如 GinIndexGistIndex 之类的索引更适合,尽管索引的选择取决于您正在使用的查询。通常,GiST 可能是 范围字段HStoreField 的一个不错的选择,而 GIN 对于 ArrayField 可能会有所帮助。

ArrayField

class ArrayField(base_field, size=None, **options)

用于存储数据列表的字段。可以使用大多数字段类型,并且将另一个字段实例作为 base_field 传递。您还可以指定 sizeArrayField 可以嵌套以存储多维数组。

如果您为字段提供 default,请确保它是一个可调用对象,例如 list(对于空默认值)或返回列表的可调用对象(例如函数)。不正确地使用 default=[] 会创建一个可变的默认值,该默认值在 ArrayField 的所有实例之间共享。

base_field

这是一个必需的参数。

指定数组的基础数据类型和行为。它应该是 Field 的子类的实例。例如,它可以是 IntegerFieldCharField。大多数字段类型都是允许的,除了处理关系数据的字段(ForeignKeyOneToOneFieldManyToManyField)和文件字段(FileFieldImageField)。

可以嵌套数组字段 - 可以将 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

ArrayField 上覆盖了 contains 查找。返回的对象将是传递的值是数据子集的对象。它使用 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

这是 contains 查找的反向 - 返回的对象将是数据是传递的值的子集的对象。它使用 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", "tutorial"])
>>> 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>]>

>>> Post.objects.filter(tags__overlap=Post.objects.values_list("tags"))
<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>]>

索引转换

索引转换索引到数组中。可以使用任何非负整数。如果它超过了数组的 size,则不会发生错误。转换后可用的查找来自 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 []>

注意

PostgreSQL 在编写原始 SQL 时使用基于 1 的索引来表示数组字段。但是,这些索引和在 slices 中使用的索引使用基于 0 的索引,以与 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>]>

注意

PostgreSQL 在编写原始 SQL 时使用基于 1 的索引来表示数组字段。但是,这些切片和在 indexes 中使用的切片使用基于 0 的索引,以与 Python 保持一致。

具有索引和切片的多维数组

在使用多维数组的索引和切片时,PostgreSQL 有一些相当深奥的行为。使用索引访问最终的基础数据始终有效,但大多数其他切片在数据库级别表现异常,并且 Django 无法以逻辑一致的方式支持它们。

HStoreField

class HStoreField(**options)

用于存储键值对的字段。使用的 Python 数据类型是 dict。键必须是字符串,值可以是字符串或空值(Python 中的 None)。

要使用此字段,您需要

  1. 在您的 INSTALLED_APPS 中添加 'django.contrib.postgres'

  2. 在 PostgreSQL 中设置 hstore 扩展

如果您跳过第一步,您将看到类似于 can't adapt type 'dict' 的错误,或者如果您跳过第二步,则会看到 type "hstore" does not exist 的错误。

注意

在某些情况下,可能需要或限制对给定字段有效的键。这可以通过使用 KeysValidator 来完成。

查询 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>]>

或使用 F() 表达式来注释键值。例如

>>> from django.db.models import F
>>> rufus = Dog.objects.annotate(breed=F("data__breed"))[0]
>>> rufus.breed
'labrador'

如果要查询的键与其他查找的名称冲突,则需要使用 hstorefield.contains 查找。

注意

键转换也可以与以下内容链接:containsicontainsendswithiendswithiexactregexiregexstartswithistartswith 查找。

警告

由于任何字符串都可能是 hstore 值中的键,因此除了下面列出的查找之外,任何其他查找都将被解释为键查找。不会引发任何错误。对于输入错误要格外小心,并始终检查您的查询是否按预期工作。

contains

HStoreField 上覆盖了 contains 查找。返回的对象是给定的 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

这是 contains 查找的反向 - 返回的对象将是对象上的键值对是传递的值的子集的对象。它使用 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 函数 avals()。例如

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

范围字段

有五种范围字段类型,对应于 PostgreSQL 中的内置范围类型。这些字段用于存储值的范围;例如事件的开始和结束时间戳,或活动适合的年龄范围。

所有范围字段都转换为 Python 中的 psycopg Range 对象,但如果不需要边界信息,也可以接受元组作为输入。默认情况下,下界包含,上界排除,即 [)(有关 不同边界 的详细信息,请参阅 PostgreSQL 文档)。对于非离散范围字段(DateTimeRangeFieldDecimalRangeField),可以使用 default_bounds 参数更改默认边界。

IntegerRangeField

class IntegerRangeField(**options)

存储整数范围。基于 IntegerField。在数据库中表示为 int4range,在 Python 中表示为 django.db.backends.postgresql.psycopg_any.NumericRange

无论在保存数据时指定了哪些边界,PostgreSQL 始终以规范形式返回范围,该范围包括下界并排除上界,即 [)

BigIntegerRangeField

class BigIntegerRangeField(**options)

存储大整数范围。基于 BigIntegerField。在数据库中表示为 int8range,在 Python 中表示为 django.db.backends.postgresql.psycopg_any.NumericRange

无论在保存数据时指定了哪些边界,PostgreSQL 始终以规范形式返回范围,该范围包括下界并排除上界,即 [)

DecimalRangeField

class DecimalRangeField(default_bounds='[)', **options)

存储浮点值范围。基于 DecimalField。在数据库中表示为 numrange,在 Python 中表示为 django.db.backends.postgresql.psycopg_any.NumericRange

default_bounds

可选。列表和元组输入的bounds值。默认值为下界包含,上界不包含,即[)(有关不同边界的详细信息,请参阅 PostgreSQL 文档)。default_bounds不适用于django.db.backends.postgresql.psycopg_any.NumericRange输入。

DateTimeRangeField

class DateTimeRangeField(default_bounds='[)', **options)

存储时间戳范围。基于DateTimeField。在数据库中表示为tstzrange,在 Python 中表示为django.db.backends.postgresql.psycopg_any.DateTimeTZRange

default_bounds

可选。列表和元组输入的bounds值。默认值为下界包含,上界不包含,即[)(有关不同边界的详细信息,请参阅 PostgreSQL 文档)。default_bounds不适用于django.db.backends.postgresql.psycopg_any.DateTimeTZRange输入。

DateRangeField

class DateRangeField(**options)

存储日期范围。基于DateField。在数据库中表示为daterange,在 Python 中表示为django.db.backends.postgresql.psycopg_any.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 django.db.backends.postgresql.psycopg_any import NumericRange

包含函数

与其他 PostgreSQL 字段一样,有三个标准的包含运算符:containscontained_byoverlap,分别使用 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查找也适用于非范围字段类型:SmallAutoFieldAutoFieldBigAutoFieldSmallIntegerFieldIntegerFieldBigIntegerFieldDecimalFieldFloatFieldDateFieldDateTimeField。例如

>>> from django.db.backends.postgresql.psycopg_any 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>]>

比较函数

范围字段支持标准查找:ltgtltegte。这些不是特别有用 - 它们首先比较下界,然后仅在必要时比较上界。这也是用于按范围字段排序的策略。最好使用特定的范围比较运算符。

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 []>
lower_inc

返回具有包含或排除下界的对象,具体取决于传递的布尔值。可以链接到BooleanField的有效查找。

>>> Event.objects.filter(ages__lower_inc=True)
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
lower_inf

返回具有无界(无限)或有界下界的对象,具体取决于传递的布尔值。可以链接到BooleanField的有效查找。

>>> Event.objects.filter(ages__lower_inf=True)
<QuerySet []>
upper_inc

返回具有包含或排除上界的对象,具体取决于传递的布尔值。可以链接到BooleanField的有效查找。

>>> Event.objects.filter(ages__upper_inc=True)
<QuerySet []>
upper_inf

根据传递的布尔值返回具有无界(无限)或有界上界的对象。可以链接到有效的查找以获取BooleanField

>>> Event.objects.filter(ages__upper_inf=True)
<QuerySet [<Event: Pub trip>]>

定义您自己的范围类型

PostgreSQL 允许定义自定义范围类型。Django 的模型和表单字段实现使用下面的基类,并且 psycopg 提供了一个 register_range() 来允许使用自定义范围类型。

class RangeField(**options)

模型范围字段的基类。

base_field

要使用的模型字段类。

range_type

要使用的范围类型。

form_field

要使用的表单字段类。应为 django.contrib.postgres.forms.BaseRangeField 的子类。

class django.contrib.postgres.forms.BaseRangeField

表单范围字段的基类。

base_field

要使用的表单字段。

range_type

要使用的范围类型。

范围运算符

class RangeOperators

PostgreSQL 提供了一组 SQL 运算符,可以与范围数据类型一起使用(有关范围运算符的完整详细信息,请参阅 PostgreSQL 文档)。此类旨在作为一种避免错别字的便捷方法。运算符名称与相应查找的名称重叠。

class RangeOperators:
    EQUAL = "="
    NOT_EQUAL = "<>"
    CONTAINS = "@>"
    CONTAINED_BY = "<@"
    OVERLAPS = "&&"
    FULLY_LT = "<<"
    FULLY_GT = ">>"
    NOT_LT = "&>"
    NOT_GT = "&<"
    ADJACENT_TO = "-|-"

RangeBoundary() 表达式

class RangeBoundary(inclusive_lower=True, inclusive_upper=False)
inclusive_lower

如果 True(默认值),则下界为包含性 '[',否则为排他性 '('

inclusive_upper

如果 False(默认值),则上界为排他性 ')',否则为包含性 ']'

RangeBoundary() 表达式表示范围边界。它可以与期望边界的自定义范围函数一起使用,例如定义 ExclusionConstraint。有关完整详细信息,请参阅 PostgreSQL 文档

返回顶部