PostgreSQL特定的模型字段

所有这些字段都可以从 django.contrib.postgres.fields 模块。

索引这些字段

IndexField.db_index 两者都创建了一个B树索引,这在查询复杂数据类型时并没有特别的帮助。索引等 GinIndexGistIndex 更适合,尽管索引的选择取决于您使用的查询。一般来说,GIST可能是 range fieldsHStoreField 杜松子酒可能对 ArrayField .

ArrayField

class ArrayField(base_field, size=None, **options)[源代码]

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

如果你给场 default 确保它是可调用的,例如 list (对于空默认值)或返回列表(如函数)的可调用项。使用不当 default=[] 创建一个可变的默认值,该默认值在 ArrayField .

base_field

这是必需的参数。

指定数组的基础数据类型和行为。它应该是的子类的实例 Field 。例如,它可以是一个 IntegerField 或者是 CharField 。允许使用大多数字段类型,但处理关系数据的字段类型除外 (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

这个 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

这是与 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>]>

索引转换

INDEX将索引转换为数组。可以使用任何非负整数。如果它超过 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 . 键必须是字符串,并且值可以是字符串或空值 (None 在 Python 中)。

要使用此字段,您需要:

  1. 添加 'django.contrib.postgres' 在你 INSTALLED_APPS .

  2. Set up the hstore extension 在PostgreSQL中。

你会看到一个错误,比如 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 查找相反。

备注

还可以使用以下链接来链接键转换: containsicontainsendswithiendswithiexactregexiregexstartswith ,以及 istartswith 查找。

警告

由于任何字符串都可以是hstore值中的键,因此除下面列出的字符串以外的任何查找都将被解释为键查找。未引发任何错误。要格外小心打字错误,并且总是检查你的查询是否按你的意愿工作。

contains

这个 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

这是与 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中内置的范围类型。这些字段用于存储一系列值;例如事件的开始和结束时间戳,或者活动适合的年龄范围。

所有范围字段都会转换为 psycopg Range objects 如果不需要边界信息,还可以接受元组作为输入。缺省值为包含下限、排除上限,即 [) (有关的详细信息,请参阅PostgreSQL文档 different bounds )。可以更改非离散范围字段的默认边界 (DateTimeRangeFieldDecimalRangeField )通过使用 default_bounds 争论。

IntegerRangeField

class IntegerRangeField(**options)[源代码]

存储一系列整数。基于一个 IntegerField 。由一个 int4range 在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange 在Python中。

不管在保存数据时指定了什么界限,PostgreSQL总是以规范形式返回一个范围,该范围包括下限,不包括上限,也就是说 [) .

BigIntegerRangeField

class BigIntegerRangeField(**options)[源代码]

存储一系列大整数。基于一个 BigIntegerField 。由一个 int8range 在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange 在Python中。

不管在保存数据时指定了什么界限,PostgreSQL总是以规范形式返回一个范围,该范围包括下限,不包括上限,也就是说 [) .

DecimalRangeField

class DecimalRangeField(default_bounds='[)', **options)[源代码]

存储一定范围的浮点值。基于一个 DecimalField 。由一个 numrange 在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange 在Python中。

default_bounds

可选的。的价值 bounds 用于列表和元组输入。缺省值为包含下限、排除上限,即 [) (有关的详细信息,请参阅PostgreSQL文档 different bounds )。 default_bounds 不用于 django.db.backends.postgresql.psycopg_any.NumericRange 投入。

DateTimeRangeField

class DateTimeRangeField(default_bounds='[)', **options)[源代码]

存储一系列时间戳。基于一个 DateTimeField 。由一个 tstzrange 在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.DateTimeTZRange 在Python中。

default_bounds

可选的。的价值 bounds 用于列表和元组输入。缺省值为包含下限、排除上限,即 [) (有关的详细信息,请参阅PostgreSQL文档 different bounds )。 default_bounds 不用于 django.db.backends.postgresql.psycopg_any.DateTimeTZRange 投入。

DateRangeField

class DateRangeField(**options)[源代码]

存储一系列日期。基于一个 DateField 。由一个 daterange 在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.DateRange 在Python中。

不管在保存数据时指定了什么界限,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 查找也适用于非范围字段类型: SmallAutoFieldAutoFieldBigAutoFieldSmallIntegerFieldIntegerFieldBigIntegerFieldDecimalFieldFloatFieldDateField ,以及 DateTimeField 。例如:

>>> 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运算符(请参见 the PostgreSQL documentation for the full details of range operators ). 这个类是用来避免打字错误的一个方便方法。运算符名称与相应查找的名称重叠。

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 (默认),上限是排他的 ')' ,否则就包含在内 ']' .

A RangeBoundary() 表达式表示范围边界。它可以与期望边界的自定义范围函数一起使用,例如定义 ExclusionConstraint . 见 the PostgreSQL documentation for the full details .