postgresql Django 1.8 ArrayField 追加和扩展

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29014966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 01:48:59  来源:igfitidea点击:

Django 1.8 ArrayField append & extend

pythondjangopostgresqldjango-ormdjango-1.8

提问by SColvin

Django 1.8 will come with new advanced field types including ArrayFieldthese rely on PostgreSQL and are implemented at a DB level.

Django 1.8将提供新的高级字段类型,包括 ArrayField,它们依赖于 PostgreSQL 并在 DB 级别实现。

PostgreSQL's array field implements an append method.

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

However I can't find any documentation on appending an item to an ArrayField. This would clearly be very useful as it would allow the field to be updated without transferring its entire contents from the db then back to it.

但是,我找不到任何有关将项目附加到ArrayField. 这显然非常有用,因为它允许更新字段,而无需将其全部内容从数据库传输回数据库。

Is this possible? If not will it be possible in future? Any pointers to docs I've missed would be much appreciated.

这可能吗?如果没有,将来有可能吗?任何指向我错过的文档的指针将不胜感激。

To clarify what I'm asking about, this would be great:

为了澄清我在问什么,这会很棒:

Note: this is fantasy code and I assume won't work (I haven't tried)

注意:这是幻想代码,我认为不起作用(我没有尝试过)

# 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')

Is there currently any way of doing this without resorting to raw sql?

目前有没有办法在不求助于原始 sql 的情况下做到这一点?

采纳答案by erik-e

I think the features you are looking for are currently not implemented (and may not be planned). Many of the Postgres contrib features originated based on this kickstarter project.

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

I find the most useful documentation for the new features come from the source code itself. Which includes a link to the original pull requestfor many of these features.

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

An important note in regards to the Array Functions mentioned, they are Functions and arguably outside the scope of a typical ORM.

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

I hope this information is useful and you find a nice solution to this issue.

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

回答by Daniil Ryzhkov

Note: OP code will absolutely work. We just need to save the model (because these is just a model field, not relation). Let's see:

注意: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!']

Going deeper

更深入

Django gets ArrayFieldas python list

Django 获取ArrayField为 python 列表

Code reference

代码参考

Everything you could do withlist, you can do with ArrayField. Even sorting

可以用list做的一切,你都可以用 ArrayField 做。偶数排序

Django saves ArrayFieldas python list

Django 保存ArrayField为 python 列表

Code reference

代码参考

These means that it saves structure and elements of python list.

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

回答by Yotam Ofek

This works:

这有效:

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()

or in an update clause:

或在更新子句中:

Post.objects.filter(created_on__lt=now() - timespan(days=30))\
    .update(tags=CombinedExpression(F('tags'), '||', Value(['old'])))

回答by Michael

Another solution is using a custom expression. I tested the following code with Django 1.11 and Python 3.6 (f-strings).

另一种解决方案是使用自定义表达式。我使用 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,
        )

The expression can be used in update():

该表达式可用于update()

Post.objects \
    .filter(pk=1) \
    .update(tags=ArrayAppend('tags', 'new tag'))

回答by lumos42

You could use django_postgres_extensions. It supports a lot of functions like append, prepend, remove, concatenate.

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

But if you are using Django 1.8 like me, you should use only the required classes from this package. That way, you won't have to change database backend too. I've pasted the required classes here. Use them as described in first link.

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