Django 1.8 ArrayField 附加和扩展
Django 1.8 ArrayField append & extend
Django 1.8 will come with new advanced field types including ArrayField 这些依赖于 PostgreSQL 并在数据库级别实现。
PostgreSQL 的数组字段implements an append method.
但是我找不到任何关于将项目附加到 ArrayField
的文档。这显然非常有用,因为它允许更新字段,而无需将其全部内容从数据库传输回数据库。
这可能吗?如果不能,将来有可能吗?任何指向我错过的文档的指针都将不胜感激。
为了澄清我在问什么,这将是很好的:
注意:这是幻想代码,我认为行不通(我没试过)
# on model:
class Post(models.Model):
tags = ArrayField(models.CharField(max_length=200))
# somewhere else:
p = Post.objects.create(tags=[str(i) for i in range(10000)])
p.tags.append('hello')
目前有什么方法可以不借助原始 sql 来做到这一点吗?
我认为您正在寻找的功能目前尚未实现(并且可能未计划)。许多 Postgres contrib 功能 originated based on this kickstarter project.
我发现新功能最有用的文档来自 source code itself. Which includes a link to the original pull request 其中许多功能。
关于提到的数组函数的重要说明,它们是函数并且可以说是 outside the scope of a typical ORM。
希望这些信息对您有用,并希望您找到解决此问题的好方法。
注意:OP 代码绝对有效。我们只需要保存模型(因为这些只是一个模型字段,而不是关系)。让我们看看:
>>> p = Post.objects.create(tags=[str(i) for i in range(10000)])
>>> p.tags.append("working!")
>>> p.save()
>>> working_post = Post.objects.get(tags__contains=["working!"])
<Post: Post object>
>>> working_post.tags[-2:]
[u'9999', u'working!']
更深入
Django 获取 ArrayField
作为 python 列表
您 could do with 列出的所有内容,您都可以使用 ArrayField 来完成。 偶数排序
Django 将 ArrayField
保存为 python 列表
这意味着它保存了 python 列表的结构和元素。
这个有效:
from django.db.models import F
from django.db.models.expressions import CombinedExpression, Value
post = Post.objects.get(id=1000)
post.tags = CombinedExpression(F('tags'), '||', Value(['hello']))
post.save()
或在更新子句中:
Post.objects.filter(created_on__lt=now() - timespan(days=30))\
.update(tags=CombinedExpression(F('tags'), '||', Value(['old'])))
您可以使用 django_postgres_extensions。它支持很多功能,如附加、前置、删除、连接。
但是如果你像我一样使用 Django 1.8,你应该只使用这个包中必需的 类。这样,您也不必更改数据库后端。我已经粘贴了所需的 类 here。按照第一个 link.
中的说明使用它们
另一个解决方案是使用自定义表达式。我用 Django 1.11 和 Python 3.6 (f-strings).
测试了以下代码
from django.db.models.expressions import Func
class ArrayAppend(Func):
function = 'array_append'
template = "%(function)s(%(expressions)s, %(element)s)"
arity = 1
def __init__(self, expression: str, element, **extra):
if not isinstance(element, (str, int)):
raise TypeError(
f'Type of "{element}" must be int or str, '
f'not "{type(element).__name__}".'
)
super().__init__(
expression,
element=isinstance(element, int) and element or f"'{element}'",
**extra,
)
表达式可以用在update()
:
Post.objects \
.filter(pk=1) \
.update(tags=ArrayAppend('tags', 'new tag'))
Django 1.8 will come with new advanced field types including ArrayField 这些依赖于 PostgreSQL 并在数据库级别实现。
PostgreSQL 的数组字段implements an append method.
但是我找不到任何关于将项目附加到 ArrayField
的文档。这显然非常有用,因为它允许更新字段,而无需将其全部内容从数据库传输回数据库。
这可能吗?如果不能,将来有可能吗?任何指向我错过的文档的指针都将不胜感激。
为了澄清我在问什么,这将是很好的:
注意:这是幻想代码,我认为行不通(我没试过)
# on model:
class Post(models.Model):
tags = ArrayField(models.CharField(max_length=200))
# somewhere else:
p = Post.objects.create(tags=[str(i) for i in range(10000)])
p.tags.append('hello')
目前有什么方法可以不借助原始 sql 来做到这一点吗?
我认为您正在寻找的功能目前尚未实现(并且可能未计划)。许多 Postgres contrib 功能 originated based on this kickstarter project.
我发现新功能最有用的文档来自 source code itself. Which includes a link to the original pull request 其中许多功能。
关于提到的数组函数的重要说明,它们是函数并且可以说是 outside the scope of a typical ORM。
希望这些信息对您有用,并希望您找到解决此问题的好方法。
注意:OP 代码绝对有效。我们只需要保存模型(因为这些只是一个模型字段,而不是关系)。让我们看看:
>>> p = Post.objects.create(tags=[str(i) for i in range(10000)])
>>> p.tags.append("working!")
>>> p.save()
>>> working_post = Post.objects.get(tags__contains=["working!"])
<Post: Post object>
>>> working_post.tags[-2:]
[u'9999', u'working!']
更深入
Django 获取 ArrayField
作为 python 列表
您 could do with 列出的所有内容,您都可以使用 ArrayField 来完成。 偶数排序
Django 将 ArrayField
保存为 python 列表
这意味着它保存了 python 列表的结构和元素。
这个有效:
from django.db.models import F
from django.db.models.expressions import CombinedExpression, Value
post = Post.objects.get(id=1000)
post.tags = CombinedExpression(F('tags'), '||', Value(['hello']))
post.save()
或在更新子句中:
Post.objects.filter(created_on__lt=now() - timespan(days=30))\
.update(tags=CombinedExpression(F('tags'), '||', Value(['old'])))
您可以使用 django_postgres_extensions。它支持很多功能,如附加、前置、删除、连接。
但是如果你像我一样使用 Django 1.8,你应该只使用这个包中必需的 类。这样,您也不必更改数据库后端。我已经粘贴了所需的 类 here。按照第一个 link.
中的说明使用它们另一个解决方案是使用自定义表达式。我用 Django 1.11 和 Python 3.6 (f-strings).
测试了以下代码from django.db.models.expressions import Func
class ArrayAppend(Func):
function = 'array_append'
template = "%(function)s(%(expressions)s, %(element)s)"
arity = 1
def __init__(self, expression: str, element, **extra):
if not isinstance(element, (str, int)):
raise TypeError(
f'Type of "{element}" must be int or str, '
f'not "{type(element).__name__}".'
)
super().__init__(
expression,
element=isinstance(element, int) and element or f"'{element}'",
**extra,
)
表达式可以用在update()
:
Post.objects \
.filter(pk=1) \
.update(tags=ArrayAppend('tags', 'new tag'))