web-dev-qa-db-ja.com

Django:モデルのリストフィールド?

私のモデルでは、トリプレットのリストを持つフィールドが必要です。例えば[[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]。このデータをデータベースに保存できるフィールドはありますか?

57
Karnivaurus

JSONを使用して文字列に変換し、文字列として保存できます。

例えば、

In [3]: json.dumps([[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]])

Out[3]: '[[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]'

クラスにメソッドを追加して、自動的に変換することができます。

import json


class Foobar(models.Model):
    foo = models.CharField(max_length=200)

    def set_foo(self, x):
        self.foo = json.dumps(x)

    def get_foo(self):
        return json.loads(self.foo)

Django 1.9とpostgresqlを使用している場合、JSONFieldという新しいクラスがあります。代わりに使用する必要があります。 ここにリンクがあります

youtube で、PostgreSQLのJSONと配列に関する良い話があります。それを見て、それは非常に良い情報を持っています。

81
Ahmed

PostgreSQLを使用している場合、ネストされたArrayFieldでArrayFieldを使用できます。 https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/

このようにして、データ構造は基礎となるデータベースに認識されます。また、ORMは特別な機能を提供します。

ただし、自分でGINインデックスを作成する必要があることに注意してください(上記のリンクを参照してください: https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/# indexing-arrayfield )。

(編集:最新のDjango LTSへの更新されたリンク。この機能は少なくとも1.8以降に存在します。)

21
Risadinha

1.10のようなDjangoのより新しいバージョンを使用していて、DBがPostgresである場合、Django-taggitまたは他の代替手段よりも使用するのが適切な新しい ArrayField があります。 Djangoフレームワークにネイティブであるため。

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,
    )
20
madmanick

役立つと思います。

 Django.dbからモデルをインポート
 import ast 
 
 class ListField(models.TextField):
 __metaclass__ = models.SubfieldBase 
 description =「pythonリストを保存する」
 
 def __init __(self、* args、** kwargs):
 super(ListField、self)。 __init __(* args、** kwargs)
 
 def to_python(self、value):
 if not value:
 value = [] 
 
 if isinstance(value、list):
 return value 
 
 return ast.literal_eval(value)
 
 def get_prep_value( self、value):
値がNoneの場合:
 return value 
 
 return unicode(value)
 
 def value_to_string( self、obj):
 value = self._get_val_from_obj(obj)
 return self.get_db_prep_value(value)
 
 class ListModel(models.Model):
 test_list = ListField()

例:

 >>> ListModel.objects.create(test_list = [[1,2,3]、[2,3,4,4]])
 
 >>> ListModel .objects.get(id = 1)
 
 >>> o = ListModel.objects.get(id = 1)
 >>> o.id 
 1L 
 >>> o.test_list 
 [[1、2、3]、[2、3、4、4]] 
 >>> 
16
Prashant Gaur

これらのサードパーティパッケージが提供するJSONフィールドを使用するだけです。

この場合、フィールド値のシリアル化を気にする必要はありません-内部で発生します。

お役に立てば幸いです。

8
alecxe

リストをフラット化し、値を CommaSeparatedIntegerField に保存できます。データベースから読み戻すときは、値を3つにグループ化するだけです。

免責事項:データベースの正規化理論によれば、コレクションを単一のフィールドに保存しない方が良いです。代わりに、それらのトリプレットの値を独自のフィールドに保存し、外部キーを介してリンクすることをお勧めします。しかし、現実の世界では、それが面倒すぎる/遅い場合があります。

1
RexE

これはかなり古いトピックですが、「Djangoリストフィールド」を検索すると返されるので、Django 3および_で動作するように変更したカスタムPythonリストフィールドコードを共有します。Django 2.現在、管理インターフェースをサポートしており、evalを使用していません(これはPrashant Gaurのコードにおける大きなセキュリティ違反です)。

from Django.db import models
from typing import Iterable

class ListField(models.TextField):
    """
    A custom Django field to represent lists as comma separated strings
    """

    def __init__(self, *args, **kwargs):
        self.token = kwargs.pop('token', ',')
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs['token'] = self.token
        return name, path, args, kwargs

    def to_python(self, value):

        class SubList(list):
            def __init__(self, token, *args):
                self.token = token
                super().__init__(*args)

            def __str__(self):
                return self.token.join(self)

        if isinstance(value, list):
            return value
        if value is None:
            return SubList(self.token)
        return SubList(self.token, value.split(self.token))

    def from_db_value(self, value, expression, connection):
        return self.to_python(value)

    def get_prep_value(self, value):
        if not value:
            return
        assert(isinstance(value, Iterable))
        return self.token.join(value)

    def value_to_string(self, obj):
        value = self.value_from_object(obj)
        return self.get_prep_value(value)
1
Yaroslav

私の現在の評判では、コメントする能力がないので、 reply by Prashant Gaur のサンプルコードのコメントを参照する回答を選択します(ありがとう、Gaur-これは役に立ちました!)- python3にはないので、彼のサンプルはpython2用です

ユニコード

機能のための以下の置換

get_prep_value(self、value):
encoding = 'utf-8'、errors = 'ignore'
decode()
unicode()メソッド
errors = 'ignore'
 import sys 
 
 ... 
 
 def get_prep_value(self、value):
値がNoneの場合:
 return value 
 if sys.version_info [0]> = 3:
 if isinstance(out_data、type(b '')):
 return value.decode(encoding = 'utf-8'、errors = 'ignore')
 else:
 if isinstance(out_data、type(b '')):
 return unicode(value、encoding = 'utf-8'、errors = 'ignore')
 return str(value)
 ... 
 

0
Oleg Artemev

バックエンドとしてGoogle App EngineまたはMongoDBを使用しており、djangoappengineライブラリを使用している場合、組み込みのListFieldがあり、これはまさに必要なことを行います。さらに、リスト内の要素を含むすべてのオブジェクトを見つけるために、リストフィールドを照会するのは簡単です。

0
speedplane