Djangoモデルに辞書を保存する方法は?
-
03-07-2019 - |
質問
一部のデータをDjangoモデルに保存する必要があります。これらのデータは、モデルのすべてのインスタンスとは限りません。
最初はモデルのサブクラス化を考えましたが、アプリケーションの柔軟性を維持しようとしています。サブクラスを使用する場合、新しい種類のオブジェクトが必要になるたびにクラス全体を作成する必要がありますが、それは良くありません。また、追加のフィールドのペアを格納するためだけに多くのサブクラスが作成されます。
辞書が最善のアプローチになると本当に感じていますが、Djangoモデルに辞書を保存することに関するDjangoのドキュメントには何もありません(または見つかりません)。
手がかりはありますか
解決
探している任意のデータのような本当に辞書なら、おそらくコンテナであるモデルとキーと値のペアである別のモデルで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ソリューションではできません。
他のヒント
この追加データを使用してクエリを実行する必要がない場合は、シリアル化された辞書として保存できます。辞書を文字列に変換するには repr
を使用し、文字列を辞書に戻すには eval
を使用します。辞書にユーザーデータがないことをevalで注意するか、safe_eval実装を使用します。
この投稿には、Googleの4番目の結果で「djangoストアオブジェクト」にアクセスしました
少し遅れましたが、 django-picklefield は私にとって良い解決策のようです。
ドキュメントの例:
使用するには、モデルにフィールドを定義するだけです:
>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>> args = PickledObjectField()
そしてあなたが好きなものを(ピクル可能であれば)フィールドに割り当てます:
>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
別のクリーンで高速なソリューションは、次の場所にあります: https://github.com/bradjasper/django- jsonfield
便宜上、簡単な手順をコピーしました。
インストール
pip install jsonfield
使用法
from django.db import models
from jsonfield import JSONField
class MyModel(models.Model):
json = JSONField()
Nedが答えたように、「一部のデータ」をクエリすることはできません。辞書アプローチを使用する場合。
辞書を保存する必要がある場合、Marty Alchinの新しい本 Pro Django に文書化されているPickleFieldクラスが最善のアプローチです。このメソッドはPythonクラスプロパティを使用して、モデルフィールドに格納されているPythonオブジェクトをオンデマンドでのみピクル/アンピクルします。
このアプローチの基本は、djangoの contibute_to_class
メソッドを使用して、モデルに新しいフィールドを動的に追加し、getattr / setattrを使用してオンデマンドでシリアル化を行います。
似たようないくつかのオンライン例の1つは、この JSONField 。
あなたが解決しようとしている問題の性質が正確にはわからないが、奇妙なことに Google App EngineのBigTable Expando 。
Expandosを使用すると、実行時にデータベースでバックアップされたオブジェクトインスタンスに追加フィールドを指定して保存できます。ドキュメントから引用するには:
import datetime
from google.appengine.ext import db
class Song(db.Expando):
title = db.StringProperty()
crazy = Song(title='Crazy like a diamond',
author='Lucy Sky',
publish_date='yesterday',
rating=5.0)
crazy.last_minute_note=db.Text('Get a train to the station.')
Google App Engineは現在、PythonとDjangoフレームワークの両方をサポートしています。これがモデルを表現する最良の方法であるかどうかを調べる価値があるかもしれません。
従来のリレーショナルデータベースモデルには、この種の列追加の柔軟性がありません。データ型が十分に単純な場合は、従来のRDBMSの哲学を破り、 @ Ned Batchelder が提案しています。ただし、RDBMSを使用する必要がある場合は、おそらくDjangoモデルの継承を使用することをお勧めします。特に、 one-toを作成します。 -派生レベルごとに1つの外部キー関係。
「モデルのすべてのインスタンスと等しくない」こと「スキーマフリーデータベース」にぴったりのように思えます。 CouchDB は、そのアプローチの代表的な子であり、あなたはそれを考慮するかもしれません。
プロジェクトで、Django ORMでうまく動作しなかったテーブルをCouchDBに移動しましたが、とても満足しています。 Django固有のCouchDBモジュールなしで couchdb-python を使用しています。データモデルの説明は、こちら。 5つの「モデル」からの動きDjangoで3つの「モデル」にDjangoと1つのCouchDB" database"実際に私のアプリケーションのコードの合計行をわずかに減らしました。
この質問は古いですが、私は同じ問題を抱えていたのでここで終了し、選択した答えは私の問題を解決できませんでした。
フロントエンドでオブジェクトとして使用するために、またはデータが必ずしも同じ構造を持たないために、辞書をDjangoまたはREST Apiに保存する場合は、使用したソリューションが役立ちます。
データをAPIに保存するときは、 json.dump()この question <で説明されているように、適切なjson形式で保存できるようにするメソッド/ a>。
この構造を使用する場合、データは既に JSON.parse()をajax(または何でも)呼び出しで。
よく考えて、各データセットの共通点を見つけてください...そしてモデルを定義してください。サブクラスの使用が必要な場合とそうでない場合があります。共通性を表す外部キーは避けるべきではありませんが、意味がある場合は推奨されます。
ランダムなデータをSQLテーブルに詰め込むことは、それが本当に非リレーショナルデータでない限り、スマートではありません。その場合は、問題を定義してください。サポートできる場合があります。
Django-Geoには&quot; DictionaryField&quot;が含まれています。役に立つかもしれません:
http:/ /code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49
一般に、データ全体をクエリする必要がない場合は、非正規化アプローチを使用して余分なクエリを回避します。ユーザー設定は非常に良い例です!
Postgresを使用している場合、hstoreフィールドを使用できます。 https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield 。
テキストフィールドと 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)