Django モデルオブジェクトを何としてでも JSON に変換する
今回は説明を省略していくので注意。
あなたは models.py にモデルを定義しているとします。
# # models.py # from django.db import models class Item(models.Model): name = CharField(max_length=50, primary_key=True) tags = models.ManyToManyField(Tag) # 別途 Tag モデルが定義されているとする
django の Model インスタンスを JSON 化する場合、以下の方法(ドキュメンテーション通り)なら(一応)問題はありません。
filter() メソッドが返す QuerySet は JSON 化しやすい。
ただし、serializers が生成する JSON では 'pk', 'fields' 等の変なキーを使わないといけない。
from django_project.application import models # models.py from django.core import serializers items = models.Item.objects.filter(name='name') # QuerySet # JSON json_serializer = serializers.get_serializer('json')() data = simplejson.dumps(items, ensure_ascii=False)
一方、get() メソッドや for 文により得られた Model インスタンスは、上記の方法ではうまく JSON 化できません。
「Item is not JSON serializable」で何度も苦しめられました。
複数の Model を辞書やリストに入れて JSON 化したい場合、これでは困ります(もちろん、直接 Model インスタンスを JSON 化する場合も)。
解決策として、独自にエンコード用の関数を定義する必要があるようです。
また、serializers ではなく simplejson モジュールを直接使用します。
変換関数は simplejson.dumps() の default 引数で指定できます。
from django_project.application import models # models.py from django.db import models as django_models # django が提供する models モジュール from django.utils import simplejson item = models.Item.objects.get(name='name') # Item モデル data = simplejson.dumps(item, ensure_ascii=False, default=encode_myway) return HttpResponse(data, mimetype='application/json') # 独自の変換関数 def encode_myway(obj): if isinstance(obj, django_models.Model): return obj.encode() # models.py のモデルに encode() メソッドを追加定義すること # encode という名前は適当に付けました elif isinstance(obj, QuerySet): return list(obj) # 空の QuerySet は list 化する else: raise TypeError(repr(obj) + " is not JSON serializable")
空の QuerySet は「TypeError: [] is not JSON serializable」となるため、上記のように list 化します。
変換用の encode() メソッドを models.py の各モデルクラスに定義します。
# # models.py # from django.db import models class Item(models.Model): name = CharField(max_length=50, primary_key=True) tags = models.ManyToManyField(Tag) # 別途 Tag モデルが定義されているとする def encode(self): return { 'name': self.name, 'tags': self.tags.all(), # ManyToMany 等は all() でエンティティ化(非 QuerySet 化) } # JSON にキーが必要ないなら return [self.name, self.tags.all()] としてもよい。
これで Model インスタンスを自由に JSON 化できます。
私は Model を含んだ辞書リスト [{'item': item}, ... ] を view.py で JSON 化した Response を作ります。
- 参考