web-dev-qa-db-ja.com

djangoでリストフィールドを作成する方法

Django(Python)でGoogle App Engine(Python)の ListProperty プロパティのようにListFieldを作成するにはどうすればよいですか?データは次のようなリストです:3,4,5,6,7,8

どのプロパティを定義する必要があり、どのようにしてそのプロパティから値をフェッチしますか?

28
Madhur

使用できるListFieldタイプでこれを再検討してください。しかし、複雑な型をリストに格納していないという事実など、いくつかの前提があります。このため、ast.literal_eval()を使用して、単純な組み込み型のみをメンバーとしてListFieldに格納できるようにしています。

_from Django.db import models
import ast

class ListField(models.TextField):
    __metaclass__ = models.SubfieldBase
    description = "Stores a python list"

    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):
        if value is 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 Dummy(models.Model):
    mylist = ListField()
_

試してみる:

_>>> from foo.models import Dummy, ListField
>>> d = Dummy()
>>> d.mylist
[]
>>> d.mylist = [3,4,5,6,7,8]
>>> d.mylist
[3, 4, 5, 6, 7, 8]
>>> f = ListField()
>>> f.get_prep_value(d.numbers)
u'[3, 4, 5, 6, 7, 8]'
_

そこには、リストがデータベースにユニコード文字列として格納されており、プルアウトされると ast.literal_eval() が実行されます。

以前、私はこのブログ投稿からこのソリューションを提案しました Djangoのカスタムフィールド

CommaSeparatedIntegerFieldの代わりに、分離した値を格納できます。オプションでトークンパラメータを指定することもできます。

_from Django.db import models

class SeparatedValuesField(models.TextField):
    __metaclass__ = models.SubfieldBase

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

    def to_python(self, value):
        if not value: return
        if isinstance(value, list):
            return value
        return value.split(self.token)

    def get_db_prep_value(self, value):
        if not value: return
        assert(isinstance(value, list) or isinstance(value, Tuple))
        return self.token.join([unicode(s) for s in value])

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)
_
35
jathanism

ここに記載されているCommaSeparatedIntegerFieldを使用してみてください: http://docs.djangoproject.com/en/1.2/ref/models/fields/#commaseparatedintegerfield

5
Isaac C.

Django-jsonfield を検討してください。利点は次のとおりです。

  • ネイティブリストオブジェクトの保存と読み込み、変換は不要
  • 十分にテストされ、成熟したソリューション
  • プロジェクト内に他の利点がある可能性があります
  • データベースと正規表現のフィルタリングをサポート(必要な場合)

また:

  • データベース間のサポート
  • Python 2.7 to Python 3.4 and Django 1.4 to 1.8
  • 本当に簡単です:)
4
oden

ヤサニズムの答えは素晴らしいですが、dumpdataコマンドを使用しようとすると、次のエラーが発生しました。

Error: Unable to serialize database: get_db_prep_value() takes at least 3 arguments (2 given)

問題は、self.get_db_prep_valueメソッドのvalue_to_string呼び出しでconnection値を提供する必要があることです(少なくとも Django 1.4.1 では、これは使用しています)。結局のところ、最初にvalue_to_stringメソッドを呼び出して不要な__init__メソッドを削除することで、何が得られるのか実際にはわかりませんでした。これは私が終わったものです:

class ListField(models.TextField):
    __metaclass__ = models.SubfieldBase
    description = "Stores a python list"

    def to_python(self, value):
        if not value:
            value = []

        if isinstance(value, list):
            return value

        converted = ast.literal_eval(value)
        if not isinstance(converted, list):
            raise ValueError('Value "%s" not a list' % converted)

        return converted
2
alukach

Postgresqlを使用している場合、Djangoは arrayfield でpostgresをサポートします。

2
Leonard2

私はこれをします:

def get_comma_field(self, field):
    data = getattr(self, field)
    if data:
        return data.split(',')
    return []


def set_comma_field(self, val, field):
    if isinstance(val, types.StringTypes):
        setattr(self, field, val)
    else:
        setattr(self, field, ','.join(val))


def make_comma_field(field):
    def getter(self):
        return get_comma_field(self, field)

    def setter(self, val):
        return set_comma_field(self, val, field)

    return property(getter, setter)

class MyModel(models.Model):
    _myfield = models.CharField(max_length=31)
    myfield = make_comma_field('_myfield')

しかし、私は今それはやり過ぎかもしれないと思います。かなりの数が必要だったので、make_comma_field関数を記述しました。

1
Aaron McMillin

簡単に言えば、リストを文字列として保存し、それを使用するときは常にast.literal_eval()を使用して、最初に文字列からリストに変換します。例えば:

import ast

class MyModel(models.Model):
    field_1 = models.any kind of field()
    list_field = models.CharField(max_length=255)

    def get_list(self):
        list = ast.literal_eval(self.list_field)
        return list

ビューなどでも同じです。保存するときは、リストに操作を行い、最後に文字列に変換します。

model.list_field = str(list)
model.save()
0
sprksh