PostgreSQL specific model fields

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

ArrayField

class ArrayField(base_field, size=None, **options)[source]

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

如果您将字段设置为default,请确保它是可调用的,例如list(空默认)或可返回列表(如函数)的可调用。 错误地使用default=[]创建了一个可变的默认值,它在ArrayField的所有实例之间共享。

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

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

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')
<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 []>

在编写原始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'])
<QuerySet [<Post: First post>, <Post: Second post>]>

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

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

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

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

索引ArrayField

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

CIText字段

class CIText(**options)[source]
Django中的新功能1.11。

一个mixin来创建由citext类型支持的不区分大小写的文本字段。 在使用之前,请阅读性能注意事项

要使用citext,在第一个CreateModel迁移操作之前,请在PostgreSQL中使用CITextExtension操作setup the citext extension

提供了使用mixin的几个字段:

class CICharField(**options)[source]
class CIEmailField(**options)[source]
class CITextField(**options)[source]

这些字段分别为CharFieldEmailFieldTextField

max_length不会在数据库中执行,因为citext的行为类似于PostgreSQL的text类型。

HStoreField

class HStoreField(**options)[source]

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

要使用此字段,您需要:

  1. 在您的INSTALLED_APPS中添加'django.contrib.postgres'
  2. Setup the hstore extension

你会看到一个错误,如不能 适应 类型 'dict'如果您跳过第一步,或类型 “hstore” / t10>如果你跳过第二个。

在Django更改1.11:

增加了存储空值的功能。 以前,他们被投入了弦。

在某些情况下,可能需要或限制对给定字段有效的键。 这可以使用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):  # __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')
<QuerySet [<Dog: Meg>]>

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

>>> Dog.objects.filter(data__breed__contains='l')
<QuerySet [<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'})
<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函数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)[source]

用于存储JSON编码数据的字段。 在Python中,数据以Python本机格式表示:字典,列表,字符串,数字,布尔和None

encoder
Django 1.11中新增。

一个可选的JSON编码类,用于序列化标准JSON序列化程序(datetimeuuid等)不支持的数据类型。 例如,你可以使用DjangoJSONEncoder类或json.JSONEncoder的任何其它子类。

当从数据库检索该值时,它将采用自定义编码器选择的格式(通常是字符串),因此需要采取额外的步骤才能将值转换回初始数据类型(Model.from_db()Field.from_db_value()是两个hook,可以用于此目的)。 反序列化需要考虑无法确定输入类型的情况。 例如,你正在返回datetime,它实际上是一个字符串,只是恰好与datetime所选择的格式相同。

如果你给这个字段一个default,那么确保它是一个可调用的,例如dict(一个空的默认值)或一个可以返回一个dict(如一个函数)的callable。 错误地使用default={}创建了一个可变的默认值,它在JSONField的所有实例之间共享。

PostgreSQL有两种本机基于JSON的数据类型:jsonjsonb 它们之间的主要区别是它们如何被存储以及如何被查询。 PostgreSQL的json字段存储为JSON的原始字符串表示形式,并且必须在基于密钥查询时即时解码。 jsonb字段的存储基于JSON的实际结构,这样允许索引。 在写入jsonb字段时,这种权衡的成本相对较小。 JSONField使用jsonb

因此,此字段需要PostgreSQL≥9.4

查询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):  # __unicode__ on Python 2
        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'})

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

如果您希望通过与另一个查找的名称进行冲突查询的密钥,请改用jsonfield.contains查找。

如果仅使用一个键或索引,则使用SQL运算符-> 如果使用多个操作符,则使用#>运算符。

警告

由于任何字符串可能是JSON对象中的一个键,所以除了下面列出的任何查找都将被解释为键查找。 不会产生错误。 请特别小心输入错误,并始终检查您的查询工作,因为你打算。

遏制和关键操作

JSONField shares lookups relating to containment and keys with HStoreField.

Range Fields

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

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

IntegerRangeField

class IntegerRangeField(**options)[source]

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

无论在保存数据时指定的边界如何,PostgreSQL总是返回一个包含下限的规范形式的范围,并排除上限;那是[)

BigIntegerRangeField

class BigIntegerRangeField(**options)[source]

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

无论在保存数据时指定的边界如何,PostgreSQL总是返回一个包含下限的规范形式的范围,并排除上限;那是[)

FloatRangeField

class FloatRangeField(**options)[source]

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

DateTimeRangeField

class DateTimeRangeField(**options)[source]

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

DateRangeField

class DateRangeField(**options)[source]

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

无论在保存数据时指定的边界如何,PostgreSQL总是返回一个包含下限的规范形式的范围,并排除上限;那是[)

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()
    start = models.DateTimeField()

    def __str__(self):  # __unicode__ on Python 2
        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

Containment functions

与其他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查找也可用于非范围字段类型:IntegerFieldBigIntegerFieldFloatFieldDateFieldDateTimeField 像这样:

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

Comparison functions

范围字段支持标准查找: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>]>

Querying using the bounds

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

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

Defining your own range types

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

class RangeField(**options)[source]

模型范围字段的基类。

base_field

要使用的模型字段类。

range_type

要使用的psycopg2范围类型。

form_field

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

class django.contrib.postgres.forms.BaseRangeField

表单范围字段的基类。

base_field

要使用的表单字段。

range_type

要使用的psycopg2范围类型。