21

Django 1.8将带有新的高级字段类型,包括 ArrayField这些依赖于 PostgreSQL 并在数据库级别实现。

PostgreSQL 的数组字段实现了一个 append 方法

但是我找不到任何关于将项目附加到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 的情况下做到这一点?

4

5 回答 5

28

注意: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 列表

代码参考

可以用列表做的所有事情,你都可以用 ArrayField 做。甚至排序

Django另存ArrayField为python列表

代码参考

这意味着它保存了 python 列表的结构和元素。

于 2015-04-08T05:09:28.070 回答
11

我认为您正在寻找的功能目前尚未实现(并且可能没有计划)。许多 Postgres contrib 特性源自这个 kickstarter 项目

我发现新功能最有用的文档来自源代码本身。其中包括指向其中许多功能的原始拉取请求的链接。

关于提到的数组函数的一个重要说明,它们是函数并且可以说超出了典型 ORM 的范围

我希望这些信息有用,并且您可以找到解决此问题的好方法。

于 2015-04-04T03:45:02.977 回答
10

这有效:

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'])))
于 2016-05-23T19:50:13.417 回答
4

另一种解决方案是使用自定义表达式。我使用 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'))
于 2017-09-29T09:04:47.083 回答
2

您可以使用django_postgres_extensions。它支持许多功能,如追加、前置、删除、连接。

但是如果你像我一样使用 Django 1.8,你应该只使用这个包中所需的类。这样,您也不必更改数据库后端。我在这里粘贴了所需的类。按照第一个链接中的说明使用它们。

于 2016-11-24T05:39:55.860 回答