[解決済み] Django の Model オブジェクトを、全てのフィールドをそのままに dict に変換します。
質問
でdjangoのModelオブジェクトをdictに変換するにはどうすればよいのでしょうか? すべて のフィールドを使用できますか? 理想的には、外部キーとeditable=Falseのフィールドが含まれます。
詳しく説明します。 以下のような django のモデルを持っているとします。
from django.db import models
class OtherModel(models.Model): pass
class SomeModel(models.Model):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
ターミナルで、次のようにしました。
other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()
これを次のような辞書に変換したい。
{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
'foreign_key': 1,
'id': 1,
'many_to_many': [1],
'normal_value': 1,
'readonly_value': 2}
満足のいく回答が得られない質問。
Djangoです。モデルのオブジェクトのセット全体を一つの辞書に変換する
Django のモデルオブジェクトを辞書に変換し、外部キーを保持するにはどうしたらいいですか?
どのように解決するのですか?
インスタンスを辞書に変換する方法は数多くあり、コーナーケースの処理と目的の結果への近さの程度は様々です。
1.
instance.__dict__
instance.__dict__
を返します。
{'_foreign_key_cache': <OtherModel: OtherModel object>,
'_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
これは圧倒的にシンプルな方法ですが、以下のような欠点があります。
many_to_many
,
foreign_key
は名前が間違っていて、2つの不要な余分なものが入っています。
2.
model_to_dict
from django.forms.models import model_to_dict
model_to_dict(instance)
を返します。
{'foreign_key': 2,
'id': 1,
'many_to_many': [<OtherModel: OtherModel object>],
'normal_value': 1}
これには
many_to_many
しかし、編集不可能なフィールドがありません。
3.
model_to_dict(..., fields=...)
from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])
を返します。
{'foreign_key': 2, 'id': 1, 'normal_value': 1}
これは、厳密には、標準の
model_to_dict
を呼び出すことができます。
4.
query_set.values()
SomeModel.objects.filter(id=instance.id).values()[0]
を返します。
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
と同じ出力です。
instance.__dict__
が、余分なフィールドはありません。
foreign_key_id
はまだ間違っていて
many_to_many
が欠落したままです。
5. カスタム機能
のコードは、django の
model_to_dict
が答えの大半を占めていました。 そのため、そのチェックを外し、多対多のフィールドの外部キーのIDを取得すると、以下のようなコードになり、希望通りの動作をするようになりました。
from itertools import chain
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
これは最も複雑なオプションですが
to_dict(instance)
は、まさに望む結果を与えてくれます。
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
6. シリアライザーの使用
Django Rest フレームワーク の ModelSerialzer を使えば、モデルからシリアライザを自動的に構築することができます。
from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = "__all__"
SomeModelSerializer(instance).data
リターン
{'auto_now_add': '2018-12-20T21:34:29.494827Z',
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
これはカスタム関数とほぼ同じですが、auto_now_addはdatetimeオブジェクトの代わりに文字列です。
ボーナスラウンド:より良いモデル印刷
Python のコマンドライン表示を改善した django モデルが欲しい場合、モデルを以下のように子クラス化します。
from django.db import models
from itertools import chain
class PrintableModel(models.Model):
def __repr__(self):
return str(self.to_dict())
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
class Meta:
abstract = True
そこで、例えば、モデルをこのように定義するとします。
class OtherModel(PrintableModel): pass
class SomeModel(PrintableModel):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
呼び出し
SomeModel.objects.first()
は、次のような出力になりました。
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
関連
-
Pythonによるjieba分割ライブラリ
-
[解決済み] 'int'オブジェクトに'__getitem__'属性がない。
-
[解決済み】SyntaxError: デフォルト以外の引数がデフォルトの引数に続く
-
[解決済み】Flaskのテンプレートが見つからない【重複あり
-
[解決済み] オブジェクトの現在のプロパティと値をすべて表示する組み込み関数はありますか?
-
[解決済み] ネストされたPythonのdictをオブジェクトに変換する?
-
[解決済み] Django のカスタムフィールドで User モデルを拡張する
-
[解決済み】Djangoのモデルインスタンスオブジェクトをクローンして、データベースに保存する方法は?
-
[解決済み】Django: モデルフィールドのリストを取得しますか?
-
[解決済み] 多対多フィールドを持つDjangoモデルのオブジェクトを作成する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ピロウズ画像色処理の具体的な活用方法
-
PythonはWordの読み書きの変更操作を実装している
-
PyQt5はユーザーログインGUIインターフェースとログイン後のジャンプを実装しています。
-
[解決済み】TypeError: 系列を <class 'float'> に変換することができません。
-
[解決済み】LogisticRegression: Pythonでsklearnを使用して、未知のラベルタイプ: '連続'を使用しています。
-
[解決済み】IndexError: invalid index to scalar variableを修正する方法
-
[解決済み】SyntaxError: デフォルト以外の引数がデフォルトの引数に続く
-
[解決済み] 保存時に、フィールドが変更されたかどうかを確認するにはどうすればよいですか?
-
[解決済み】「datetime.datetime not JSON serializable」を克服する方法とは?
-
[解決済み] <Django object>はJSONシリアライザブルではありません。