web-dev-qa-db-ja.com

Djangoモデルに辞書を保存する方法は?

Djangoモデルにデータを保存する必要があります。これらのデータは、モデルのすべてのインスタンスと同じではありません。

最初はモデルをサブクラス化することを考えましたが、アプリケーションの柔軟性を維持しようとしています。サブクラスを使用する場合、新しい種類のオブジェクトが必要になるたびにクラス全体を作成する必要がありますが、それは良くありません。また、追加のフィールドのペアを格納するためだけに多くのサブクラスを作成します。

辞書が最善のアプローチだと思いますが、Djangoモデルに辞書を保存することに関するDjangoドキュメントには何もありません(または見つかりません)。

手がかりはありますか?

50
AticusFinch

探している任意のデータのような辞書である場合は、コンテナであるモデルとキーと値のペアである別のモデルで2レベルのセットアップを使用できます。コンテナのインスタンスを作成し、各Key-Valueインスタンスを作成し、一連のKey-Valueインスタンスをコンテナインスタンスに関連付けます。何かのようなもの:

class Dicty(models.Model):
    name      = models.CharField(max_length=50)

class KeyVal(models.Model):
    container = models.ForeignKey(Dicty, db_index=True)
    key       = models.CharField(max_length=240, db_index=True)
    value     = models.CharField(max_length=240, db_index=True)

きれいではありませんが、DBを使用して辞書の内部にアクセス/検索できるのに対し、pickle/serializeソリューションはそうではありません。

37
Parand

この追加データのいずれかでクエリする必要がない場合は、serialized dictionaryとして保存できます。 reprを使用して辞書をストリングに変換し、evalを使用してストリングを辞書に戻します。辞書にユーザーデータがないことをevalで注意するか、safe_eval実装。

たとえば、createupdateおよびviewsメソッドでは、次を追加できます。

if isinstance(request.data, dict) == False:
    req_data = request.data.dict().copy()
else:
    req_data = request.data.copy()

dict_key = 'request_parameter_that_has_a_dict_inside'
if dict_key in req_data.keys() and isinstance(req_data[dict_key], dict):
    req_data[dict_key] = repr(req_data[dict_key])
15
Ned Batchelder

「Djangoストアオブジェクト」に対するGoogleの4番目の結果によってこの投稿に行きました。

少し遅れましたが、 Django-picklefield は私にとっては良い解決策のようです。

ドキュメントの例:

使用するには、モデルにフィールドを定義するだけです:

>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>>     args = PickledObjectField()

そして、あなたが好きなものを(ピクル可能であれば)フィールドに割り当てます:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
11
Stéphane

別のクリーンで高速なソリューションはここにあります: https://github.com/bradjasper/Django-jsonfield

便宜上、簡単な手順をコピーしました。

インストール

pip install jsonfield

使用法

from Django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()
11
odedfos

Nedが答えたように、ディクショナリアプローチを使用する場合、「一部のデータ」をクエリすることはできません。

それでも辞書を保存する必要がある場合、Marty Alchinの新しい本Pro Djangoに文書化されているPickleFieldクラスが最善のアプローチです。このメソッドは、Pythonクラスプロパティを使用して、モデルフィールドに格納されているpythonオブジェクトをオンデマンドでピクル/アンピクルします。

このアプローチの基本は、Djangoの contibute_to_class メソッドを使用して新しいフィールドをモデルに動的に追加し、getattr/setattrを使用してオンデマンドでシリアル化することです。

似たようなオンラインの例の1つは、この JSONField の定義です。

7
Van Gale

「モデルのすべてのインスタンスに等しくない」ということは、「スキーマフリーデータベース」にぴったりのように思えます。 CouchDB はそのアプローチのポスターの子であり、あなたはそれを考慮するかもしれません。

プロジェクトで、Django ORMで非常にナイスなプレイをしたことがないテーブルをいくつか、CouchDBに移動しました。とても満足しています。 couchdb-python なしでDjango固有のCouchDBモジュールのいずれか。データモデルの説明を見つけることができます こちら 。Django= to 3 "models"の5つの「モデル」からの動きin Djangoと1つのCouchDB "データベース"は、実際に私のアプリケーションのコードの合計行をわずかに減らしました。

3
max

そうでなければ構造化されたデータを単一の列に詰め込むのを控える必要があることに同意します。しかし、それをしなければならない場合、Djangoには XMLField ビルドインがあります。

JSONField at Django snipplets。

3
muhuk

この質問は古いですが、私は同じ問題を抱えていたので、ここで終了し、選択した答えは私の問題を解決できませんでした。

辞書をDjangoまたはREST Api、フロントエンドのオブジェクトとして使用するか、データが必ずしも同じ構造で、私が使用したソリューションが役立ちます。

APIにデータを保存するときは、 json.dump() メソッドを使用して、この question で説明されているように、適切なjson形式で保存できるようにします。

この構造を使用する場合、データはすでに適切なjson形式であり、ajax(または何でも)呼び出しで JSON.parse() でフロントエンドで呼び出されます。

3
Lucas Colzani

Django-Geoには、役立つと思われる「DictionaryField」が含まれています。

http://code.google.com/p/Django-geo/source/browse/trunk/fields.py?r=13#49

一般に、データ全体をクエリする必要がない場合は、非正規化アプローチを使用して余分なクエリを回避します。ユーザー設定は非常に良い例です!

2
jb.

考え直して、各データセットの共通点を見つけてから、モデルを定義してください。サブクラスの使用が必要な場合とそうでない場合があります。共通性を表す外部キーは避けるべきではありませんが、意味がある場合は推奨されます。

ランダムデータをSQLテーブルに詰め込むのは、それが本当に非リレーショナルデータでない限り、賢明ではありません。その場合は、問題を定義してください。サポートできる場合があります。

2
Daniel Naab

Postgresを使用している場合、hstoreフィールドを使用できます: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield

1
Scott Stafford

テキストフィールドとjson.loads()/json.dumps()を使用します

models.py

import json
from Django.db import models

class Item(models.Model):
    data = models.TextField(blank=True, null=True, default='{}')

    def save(self, *args, **kwargs):
        ## load the current string and
        ## convert string to python dictionary
        data_dict = json.loads(self.data)

        ## do something with the dictionary
        for something in somethings:
            data_dict[something] = some_function(something)

        ## if it is empty, save it back to a '{}' string,
        ## if it is not empty, convert the dictionary back to a json string
        if not data_dict:
            self.data = '{}'
        else:
            self.data = json.dumps(data_dict)


        super(Item, self).save(*args, **kwargs)

0
Grady Woodruff