Djangoでモデルインスタンスをどのようにシリアル化しますか?


157

モデルクエリセットをシリアル化する方法に関するドキュメントはたくさんありますが、モデルインスタンスのフィールドをJSONにシリアル化するにはどうすればよいですか?


1つのオブジェクトのクエリセットをシリアル化できるように見えますが、django.coreこれを行うためにクラスを使用することはできません。クエリセットのシリアル化を使用しない特別な理由はありますか?
ジャックM.

1
querysetシリアライザーは、結果を必要以上に2つの層にラップします。したがって、data.nameの代わりにdata [0] .fields.nameを実行する必要があります。
Jason Christa、

私もそう思っていました。私がdjangoバックエンド用のGWTインターフェースを書いているときに、同じ問題に遭遇しました。デビッドが何かに興味を持っているようです。
ジャックM.

回答:


240

リストを使用して必要なオブジェクトをラップすることは簡単で、djangoシリアライザがそれを正しくシリアル化するために必要なことはすべてこれにあります。例:

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])

9
しかし、それに応じて、シリアル化されたオブジェクトに到達するには、JSONオブジェクトのゼロ要素にインデックスを付ける必要があります。ただ注意すべき点があります。
Davor

10
そして、すべての参照オブジェクトをルートオブジェクトとともにシリアル化するのはどうですか?
パウェロク2011年

1
[0]@DavorLucicが提案するように、最後の行の終わりにしたくないですか?また、リストリテラルの末尾にコンマを付ける必要はありません(PEP8が大好きなため;)。
ホブ2014年

逆シリアル化には、追加の手順も必要です。stackoverflow.com/a/29550004/2800876を
Zags

4
これは私にはうまくいきませんでした。DjangoはAttributeError 'tuple'オブジェクトに属性 '_meta'をスローしません
adamF

71

モデルインスタンスのリストを処理する場合、使用できる最善の方法はを使用することでありserializers.serialize()、ニーズに完全に適合します。

ただし、オブジェクトではなく単一のオブジェクトをシリアル化しようとすると、問題が発生しlistます。そうmodel_to_dictすれば、さまざまなハックを取り除くために、Djangoを使用するだけです(私が間違っていない場合serializers.serialize()は、それに依存しています)。

from django.forms.models import model_to_dict

# assuming obj is your model instance
dict_obj = model_to_dict( obj )

json.dumpsこれで、jsonにシリアル化するための1つのストレートコールが必要になります。

import json
serialized = json.dumps(dict_obj)

それでおしまい!:)


6
これはUUIDフィールドで失敗します。それ以外の場合はクリアする必要があります
Alvin

2
datetimeフィールドで失敗します。json.loads(serialize('json', [obj]))[0]シリアライザがいる間にこの方法で解決しましたdjango.core.serializers.serialize
Lal Zada

43

配列ラッパーを回避するには、応答を返す前にそれを削除します。

import json
from django.core import serializers

def getObject(request, id):
    obj = MyModel.objects.get(pk=id)
    data = serializers.serialize('json', [obj,])
    struct = json.loads(data)
    data = json.dumps(struct[0])
    return HttpResponse(data, mimetype='application/json')

この件についても興味深い投稿を見つけました。

http://timsaylor.com/convert-django-model-instances-to-dictionaries

django.forms.models.model_to_dictを使用しており、ジョブに最適なツールのように見えます。


9
これがdjangoで単一のモデルをシリアル化する最良の方法である場合、jsonを逆シリアル化してシリアル化する必要がないため、それは恐ろしいことです。
ハーバート

@ハーバート、たぶん。しかし、それはあります。あなたがより良い方法を持っているなら、私はすべて耳です。単一のオブジェクトのフェッチとデエンコーディングは、リソースを大量に消費することはないため、これには実用的な欠点はありません。ホラーを隠したい場合は、新しいメソッドとして、ヘルパー関数にするか、オブジェクトを拡張/ミックスインします。
ジュリアン

1
恐怖を隠すことは問題ではなく、おそらくこの解決策でさえありません。驚いたのは、これがジャンゴの最良の方法だということです。
ハーバート

13

これには良い答えがあり、言及されていないことに驚いています。数行で、日付、モデル、その他すべてを処理できます。

モデルを処理できるカスタムエンコーダーを作成します。

from django.forms import model_to_dict
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Model

class ExtendedEncoder(DjangoJSONEncoder):

    def default(self, o):

        if isinstance(o, Model):
            return model_to_dict(o)

        return super().default(o)

json.dumpsを使用するときに使用します

json.dumps(data, cls=ExtendedEncoder)

これで、モデル、日付、およびすべてをシリアル化できるようになり、配列に入れたり、シリアル化してシリアル化したりする必要がなくなりました。あなたが持っているものはすべてカスタムに追加することができますdefaultメソッドにます。

DjangoのネイティブJsonResponseを次のように使用することもできます。

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)
``

3
このソリューションはシンプルでエレガントです。エンコーダはjson.dumpsjson.dumpメソッドの両方で使用できます。この方法では、jsonに変換する前にカスタムオブジェクトを使用するか、別のメソッド呼び出しを追加するため、アプリケーションのワークフローを変更する必要はありません。エンコーダーに変換コードを追加するだけで準備完了です。
Claudiu

11

相互運用性のためにDjangoモデルインスタンスのデータ構造をシリアル化する必要があるようです。他の投稿者は正解です。シリアル化されたフォームをDjangoのapiを介してデータベースにクエリを実行できるpythonアプリケーションで使用したい場合は、1つのオブジェクトでクエリセットをシリアル化する必要があります。一方、データベースに触れたり、Djangoを使用したりせずに、モデルインスタンスを別の場所に再度インフレートする方法が必要な場合は、少し作業が必要です。

これが私がすることです:

まず、demjson変換に使用します。それはたまたま最初に見つけたものですが、それが最善ではないかもしれません。私の実装はその機能の1つに依存していますが、他のコンバーターでも同様の方法があるはずです。

次に、json_equivalentシリアル化が必要になる可能性のあるすべてのモデルにメソッドを実装します。これはの魔法の方法ですがdemjson、どの実装を選択する場合でも、おそらくこれを検討したいものです。直接変換可能なオブジェクトjson(つまり、配列または辞書)を返すという考え方です。本当にこれを自動的に実行したい場合:

def json_equivalent(self):
    dictionary = {}
    for field in self._meta.get_all_field_names()
        dictionary[field] = self.__getattribute__(field)
    return dictionary

これは、完全にフラットなデータ構造(なしForeignKeys、データベース内の数値と文字列のみなど)がない限り、役に立ちません。それ以外の場合は、このメソッドを実装する正しい方法を真剣に検討する必要があります。

第三に、電話をかけdemjson.JSON.encode(instance)、あなたはあなたが欲しいものを持っています。


私はまだコードを試していませんが、コードのエラーを指摘したかっただけです。これはinstance._meta.get_all_field_names()であり、getattributeは関数であるため、[]ではなく()が必要です。
Jason Christa

FKに加えて、これは日時フィールドでは機能しません(demjson.JSON.encodeに魔法がない場合)
Skylar Saveland

8

モデルから単一のオブジェクトをシリアル化する方法を尋ねていて、クエリセットでオブジェクトを1つだけ取得することがわかっている場合(たとえば、objects.getを使用)、次のようなものを使用します。

import django.core.serializers
import django.http
import models

def jsonExample(request,poll_id):
    s = django.core.serializers.serialize('json',[models.Poll.objects.get(id=poll_id)])
    # s is a string with [] around it, so strip them off
    o=s.strip("[]")
    return django.http.HttpResponse(o, mimetype="application/json")

次のような形になります。

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}

しかし、これは外側の角括弧だけでなく、すべての角括弧を取り除きます。いい?"o = s [1:-1]"?
ジュリアン

5

私はモデルにシリアル化メソッドを追加することでこの問題を解決しました:

def toJSON(self):
    import simplejson
    return simplejson.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))

以下は、ワンライナーを嫌う人と同等の詳細です:

def toJSON(self):
    fields = []
    for field in self._meta.fields:
        fields.append(field.name)

    d = {}
    for attr in fields:
        d[attr] = getattr(self, attr)

    import simplejson
    return simplejson.dumps(d)

_meta.fields インスタンスおよびモデル自体からアクセスできるモデルフィールドの順序付きリストです。


3
アイデアは最初は良いように見えるかもしれませんが、このアプローチを使用することには結果があることを指摘する必要があります。特定のシリアル化出力をモデルに結び付けています。
Jonas Geiregat、2013年

@JonasGeiregatこのメソッドはモデルごとに定義されているため、このアプローチの何が問題になっていますか?悲しいことに、これはフィールドとインスタンスの主キーの両方を含むjsonオブジェクトを返す唯一の方法のようです。
dopatraman

5

これが私の解決策です。JSONを簡単にカスタマイズしたり、関連するレコードを整理したりできます。

まず、モデルにメソッドを実装します。私はそうですjsonが、あなたは好きなようにそれを呼び出すことができます、例えば:

class Car(Model):
    ...
    def json(self):
        return {
            'manufacturer': self.manufacturer.name,
            'model': self.model,
            'colors': [color.json for color in self.colors.all()],
        }

次に、私が行うビューでは:

data = [car.json for car in Car.objects.all()]
return HttpResponse(json.dumps(data), content_type='application/json; charset=UTF-8', status=status)

Python 3では、次のようになりますcar.json()
T.Coutlakis

4

リストを使用して、問題を解決します

ステップ1:

 result=YOUR_MODELE_NAME.objects.values('PROP1','PROP2').all();

ステップ2:

 result=list(result)  #after getting data from model convert result to list

ステップ3:

 return HttpResponse(json.dumps(result), content_type = "application/json")

これは、裸のオブジェクトではなく、(オブジェクトの)json配列としてシリアル化されるようです。これは、OPが尋ねたものです。つまり、これは通常のシリアル化メソッドと同じです。
ジュリアン、

1
これは、JSONシリアル化エラーで失敗します。クエリセットオブジェクトはシリアライズ可能ではありません
dopatraman

4

シリアル化および逆シリアル化するには、以下を使用します。

from django.core import serializers

serial = serializers.serialize("json", [obj])
...
# .next() pulls the first object out of the generator
# .object retrieves django object the object from the DeserializedObject
obj = next(serializers.deserialize("json", serial)).object

「ジェネレーターオブジェクトには属性 'next'がありません。何か案が?
user2880391

1
@ user2880391 Python 3向けに更新しました。修正しますか?
Zags

4

.values() モデルインスタンスをJSONに変換するために必要なものです。

.values()のドキュメント: https

Projectというモデルでの使用例。

注:私はDjango Rest Frameworkを使用しています

    @csrf_exempt
    @api_view(["GET"])
    def get_project(request):
        id = request.query_params['id']
        data = Project.objects.filter(id=id).values()
        if len(data) == 0:
            return JsonResponse(status=404, data={'message': 'Project with id {} not found.'.format(id)})
        return JsonResponse(data[0])

有効なIDの結果:

{
    "id": 47,
    "title": "Project Name",
    "description": "",
    "created_at": "2020-01-21T18:13:49.693Z",
}

3

単一のモデルオブジェクトjson応答としてクライアントに返したい場合は、次の簡単な解決策を実行できます。

from django.forms.models import model_to_dict
from django.http import JsonResponse

movie = Movie.objects.get(pk=1)
return JsonResponse(model_to_dict(movie))

2

Django Serializerpythonフォーマットで使用し、

from django.core import serializers

qs = SomeModel.objects.all()
serialized_obj = serializers.serialize('python', qs)

jsonpython形式の違いは何ですか?

jsonような形式は、結果が返されstr、一方pythonで結果を返すのいずれかlist、またはOrderedDict


それは残念です
JPG

私はOrderedDict、ではなくdict
user66081

1

インスタンスをシリアル化できないようです。1つのオブジェクトのQuerySetをシリアル化する必要があります。

from django.core import serializers
from models import *

def getUser(request):
    return HttpResponse(json(Users.objects.filter(id=88)))

svnはdjango のリリースを使い果たしたので、これは以前のバージョンにはないかもしれません。


1
ville = UneVille.objects.get(nom='lihlihlihlih')
....
blablablab
.......

return HttpResponse(simplejson.dumps(ville.__dict__))

私はインスタンスの口述を返します

したがって、{'field1':value、 "field2":value、....}のようなものを返します


これは壊れます:TypeError: <django.db.models.base.ModelState object at 0x7f2b3bf62310> is not JSON serializable
Julio Marins

1

この方法はどうですか:

def ins2dic(obj):
    SubDic = obj.__dict__
    del SubDic['id']
    del SubDic['_state']
return SubDic

または、不要なものを除外します。


0

これらの答えはすべて、私がフレームワークから期待するもの、最も簡単な方法と比較して少しハックでした。私がはるかに、残りのフレームワークを使用していると思います。

rep = YourSerializerClass().to_representation(your_instance)
json.dumps(rep)

これはシリアライザを直接使用し、それに定義したフィールドや関連などを尊重します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.