PostgreSQL specific model fields

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

ArrayField

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

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

base_field

这是必需的参数。

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

可以嵌套数组字段 - 可以将ArrayField的实例指定为base_field例如:

from django.db import models
from django.contrib.postgres.fields import ArrayField

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填充值。

Querying ArrayField

对于ArrayField,有一些自定义查找和变换。我们将使用以下示例模型:

from django.db import models
from django.contrib.postgres.fields import ArrayField

class Post(models.Model):
    name = models.CharField(max_length=200)
    tags = ArrayField(models.CharField(max_length=200), blank=True)

    def __str__(self):  # __unicode__ on Python 2
        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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__contains=['django'])
[<Post: First post>, <Post: Third post>]

>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
[<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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
[<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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
[<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)
[<Post: Second post>]

Index transforms

这类变换允许您在查询中索引到数组。可以使用任何非负整数。如果超过数组的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')
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__1__iexact='Django')
[<Post: First post>]

>>> Post.objects.filter(tags__276='javascript')
[]

注意

在编写原始SQL时,PostgreSQL对数组字段使用基于1的索引。但是,这些索引和slices使用基于0的索引与Python一致。

Slice transforms

这类变换允许你取一个数组的切片。可以使用任何两个非负整数,由单个下划线分隔。转换后可用的查找不会更改。例如:

>>> 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'])
[<Post: First post>]

>>> Post.objects.filter(tags__0_2__contains='thoughts')
[<Post: First post>, <Post: Second post>]

注意

在编写原始SQL时,PostgreSQL对数组字段使用基于1的索引。然而,这些切片和indexes使用基于0的索引来与Python一致。

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

当在多维数组上使用索引和切片时,PostgreSQL有一些相当深奥的行为。它将始终使用索引来达到最终的底层数据,但大多数其他切片在数据库级别上表现奇怪,不能以Django的逻辑一致方式支持。

Indexing ArrayField

目前使用db_index将创建一个btree索引。这不提供特别重要的帮助查询。更有用的索引是GIN索引,您应该使用RunSQL操作创建索引。

HStoreField

class HStoreField(**options)

用于存储字符串到字符串的映射的字段。使用的Python数据类型是dict

要使用此字段,您需要:

  1. 在您的INSTALLED_APPS中添加'django.contrib.postgres'
  2. 在第一个CreateModelAddField操作之前,通过使用HStoreExtension操作添加迁移,在PostgreSQL中设置hstore扩展。

You’ll see an error like can't adapt type 'dict' if you skip the first step, or type "hstore" does not exist if you skip the second.

注意

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

Querying 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):  # __unicode__ on Python 2
        return self.name

Key lookups

要基于给定的键进行查询,只需使用该键作为查找名称:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie'})

>>> Dog.objects.filter(data__breed='collie')
[<Dog: Meg>]

您可以在键查找后链接其他查找:

>>> Dog.objects.filter(data__breed__contains='l')
[<Dog: Rufus>, <Dog: Meg>]

如果您希望查询的键与另一个查找的名称冲突,则需要使用hstorefield.contains查找。

警告

因为任何字符串都可能是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'})
[<Dog: Rufus>, <Dog: Meg>]

>>> Dog.objects.filter(data__contains={'breed': 'collie'})
[<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'})
[<Dog: Meg>, <Dog: Fred>]

>>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
[<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')
[<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'])
[<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'])
[<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'])
[<Dog: Meg>]

Range Fields

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

所有范围字段都转换为python中的psycopg2 Range objects,但如果不需要边界信息,也接受元组作为输入。默认值为下限,上限为排除。

IntegerRangeField

class IntegerRangeField(**options)

存储整数范围。基于IntegerField由数据库中的int4range和Python中的NumericRange表示。

BigIntegerRangeField

class BigIntegerRangeField(**options)

存储大整数的范围。基于BigIntegerField由数据库中的int8range和Python中的NumericRange表示。

FloatRangeField

class FloatRangeField(**options)

存储浮点值的范围。基于FloatField在数据库中由numrange表示,在Python中由NumericRange表示。

DateTimeRangeField

class DateTimeRangeField(**options)

存储时间戳范围。基于DateTimeField在数据库中由tztsrange表示,在Python中由DateTimeTZRange表示。

DateRangeField

class DateRangeField(**options)

存储日期范围。基于DateField在数据库中由daterange表示,在Python中由DateRange表示。

Querying Range Fields

对于范围字段,有许多自定义查找和变换。它们可用于所有上述字段,但我们将使用以下示例模型:

from django.contrib.postgres.fields import IntegerRangeField
from django.db import models

class Event(models.Model):
    name = models.CharField(max_length=200)
    ages = IntegerRangeField()

    def __str__(self):  # __unicode__ on Python 2
        return self.name

我们还将使用以下示例对象:

>>> Event.objects.create(name='Soft play', ages=(0, 10))
>>> Event.objects.create(name='Pub trip', ages=(21, None))

NumericRange

>>> from psycopg2.extras import NumericRange

Containment functions

As with other PostgreSQL fields, there are three standard containment operators: contains, contained_by and overlap, using the SQL operators @>, <@, and && respectively.

contains
>>> Event.objects.filter(ages__contains=NumericRange(4, 5))
[<Event: Soft play>]
contained_by
>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
[<Event: Soft play>]
overlap
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
[<Event: Soft play>]

Comparison functions

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

fully_lt

返回的范围严格小于通过的范围。换句话说,返回范围中的所有点都小于通过范围中的所有点。

>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
[<Event: Soft play>]
fully_gt

返回的范围严格大于传递的范围。换句话说,返回范围中的所有点都大于通过范围中的所有点。

>>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
[<Event: Pub trip>]
not_lt

返回的范围不包含小于传递范围的任何点,也就是说返回范围的下限至少是传递范围的下限。

>>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
[<Event: Soft play>, <Event: Pub trip>]
not_gt

返回的范围不包含大于传递范围的任何点,即返回范围的上限最多为传递范围的上限。

>>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
[<Event: Soft play>]
adjacent_to

返回的范围与传递的范围共享绑定。

>>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
[<Event: Soft play>, <Event: Pub trip>]

Querying using the bounds

有三个变换可用于查询。您可以提取下限或上限,或基于空的查询。

startswith

返回的对象具有给定的下限。可以链接到基本字段的有效查找。

>>> Event.objects.filter(ages__startswith=21)
[<Event: Pub trip>]
endswith

返回的对象具有给定的上限。可以链接到基本字段的有效查找。

>>> Event.objects.filter(ages__endswith=10)
[<Event: Soft play>]
isempty

返回的对象是空范围。可以链接到BooleanField的有效查找。

>>> Event.objects.filter(ages__isempty=True)
[]

Defining your own range types

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范围类型。