所有这些字段都可以从 django.contrib.postgres.fields
模块。
Index
和 Field.db_index
两者都创建B树索引,这在查询复杂数据类型时并没有特别有帮助。等指标 GinIndex
和 GistIndex
更适合,尽管索引选择取决于您正在使用的查询。一般来说,GiST可能是 range fields 和 HStoreField
,和杜松子酒可能对 ArrayField
。
ArrayField
¶用于存储数据列表的字段。大多数字段类型都可以使用,并且您可以传递另一个字段实例作为 base_field
.您还可以指定 size
。 ArrayField
可以嵌套以存储多维数组。
如果你给场 default
确保它是可调用的,例如 list
(对于空默认值)或返回列表(如函数)的可调用项。使用不当 default=[]
创建一个可变的默认值,该默认值在 ArrayField
.
这是必需的参数。
指定数组的基础数据类型和行为。它应该是的子类的实例 Field
。例如,它可以是一个 IntegerField
或者是 CharField
。允许使用大多数字段类型,但处理关系数据的字段类型除外 (ForeignKey
, OneToOneField
和 ManyToManyField
)和文件字段( FileField
和 ImageField
)。
可以嵌套数组字段-可以指定 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,
)
数据库和模型之间的值转换、数据和配置的验证以及序列化都委托给底层的基字段。
这是一个可选参数。
如果传递,数组将具有指定的最大大小。这将传递到数据库,尽管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
¶用于存储键值对的字段。使用的python数据类型是 dict
. 键必须是字符串,并且值可以是字符串或空值 (None
在 Python 中)。
要使用此字段,您需要:
添加 'django.contrib.postgres'
在你 INSTALLED_APPS
.
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
查找相反。
备注
还可以使用以下链接来链接键转换: contains
, icontains
, endswith
, iendswith
, iexact
, regex
, iregex
, startswith
,以及 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 )。可以更改非离散范围字段的默认边界 (DateTimeRangeField
和 DecimalRangeField
)通过使用 default_bounds
争论。
IntegerRangeField
¶存储一系列整数。基于一个 IntegerField
。由一个 int4range
在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange
在Python中。
无论保存数据时指定的边界如何,PostgreSQL始终以规范形式返回一个范围,其中包括下限并排除上限,即 [)
。
BigIntegerRangeField
¶存储一系列大整数。基于一个 BigIntegerField
。由一个 int8range
在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange
在Python中。
无论保存数据时指定的边界如何,PostgreSQL始终以规范形式返回一个范围,其中包括下限并排除上限,即 [)
。
DecimalRangeField
¶存储一定范围的浮点值。基于一个 DecimalField
。由一个 numrange
在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.NumericRange
在Python中。
可选的。的价值 bounds
用于列表和元组输入。缺省值为包含下限、排除上限,即 [)
(有关的详细信息,请参阅PostgreSQL文档 different bounds )。 default_bounds
不用于 django.db.backends.postgresql.psycopg_any.NumericRange
投入。
DateTimeRangeField
¶存储一系列时间戳。基于一个 DateTimeField
。由一个 tstzrange
在数据库中,并且一个 django.db.backends.postgresql.psycopg_any.DateTimeTZRange
在Python中。
可选的。的价值 bounds
用于列表和元组输入。缺省值为包含下限、排除上限,即 [)
(有关的详细信息,请参阅PostgreSQL文档 different bounds )。 default_bounds
不用于 django.db.backends.postgresql.psycopg_any.DateTimeTZRange
投入。
DateRangeField
¶范围字段有许多自定义查找和转换。它们在上述所有字段上都可用,但我们将使用以下示例模型:
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字段一样,有三个标准的包含运算符: 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
查找也适用于非范围字段类型: SmallAutoField
, AutoField
, BigAutoField
, SmallIntegerField
, IntegerField
, BigIntegerField
, DecimalField
, FloatField
, DateField
,以及 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>]>
范围字段支持标准查找: lt
, gt
, 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 []>
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()
以允许使用自定义范围类型。
模型范围字段的基类。
要使用的模型字段类。
要使用的范围类型。
要使用的窗体字段类。应该是的子类 django.contrib.postgres.forms.BaseRangeField
.
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 = "-|-"
如果 True
(默认),下限是包含的 '['
,否则就是独家的 '('
。
如果 False
(默认),上限是排他性的 ')'
,否则就是包容的 ']'
。
A RangeBoundary()
表达表示范围边界。它可以与预期边界的自定义范围函数一起使用,例如定义边界 ExclusionConstraint
。看见 the PostgreSQL documentation for the full details 。
7月 22, 2024