web-dev-qa-db-ja.com

Django 1.8 ArrayField append&extend

Django 1.8 ArrayFieldを含む新しい高度なフィールドタイプが付属します これらはPostgreSQLに依存し、DBレベルで実装されます。

PostgreSQLの配列フィールド 追加メソッドを実装します

ただし、アイテムを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に頼らずにこれを行う方法はありますか?

17
SColvin

あなたが探している機能は現在実装されていないと思います(そして計画されていないかもしれません)。 Postgresの貢献機能の多く このキックスタータープロジェクトに基づいて作成されました

新機能の最も有用なドキュメントは ソースコード自体 から来ていると思います。これには、これらの機能の多くについて、元の プルリクエスト へのリンクが含まれています。

言及された配列関数に関する重要な注意点は、それらは関数であり、間違いなく 典型的なORMの範囲外 です。

この情報がお役に立てば幸いです。この問題に対する優れた解決策が見つかります。

10
erik-e

注: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 list

コード参照

あなたが でできる リストのすべて、あなたはArrayFieldで行うことができます。 並べ替えも

DjangoはArrayFieldをpython list)として保存します

コード参照

これは、pythonリストの構造と要素を保存することを意味します。

21
Daniil Ryzhkov

これは機能します:

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'])))
9
Yotam Ofek

別の解決策は、カスタム式を使用することです。次のコードを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'))
_
3
Michael

Django_postgres_extensions を使用できます。追加、追加、削除、連結などの多くの機能をサポートしています。

しかし、私のようにDjango 1.8を使用している場合は、このパッケージの必要なクラスのみを使用する必要があります。そうすれば、データベースバックエンドも変更する必要がありません。必要なものを貼り付けましたクラス ここ 。最初のリンクで説明されているように使用します。

2
user2485594