Bagaimana Anda membuat serial contoh model di Django?

159

Ada banyak dokumentasi tentang cara membuat serialisasi Model QuerySet tetapi bagaimana Anda hanya membuat serial ke JSON bidang-bidang Model Instance?

Jason Christa
sumber
Meskipun sepertinya Anda bisa membuat serial suatu queryset dari 1 objek, Anda tidak bisa menggunakan kelas dari django.coreuntuk melakukan ini. Ada alasan khusus untuk tidak menggunakan serialisasi queryset?
Jack M.
1
Serializer queryset membungkus hasilnya dalam dua lapisan lebih banyak dari yang seharusnya. Jadi, Anda harus melakukan data [0] .fields.name daripada data.name.
Jason Christa
Itulah yang saya pikir. Saya mengalami masalah yang sama ketika saya sedang menulis antarmuka GWT untuk backend Django. Sepertinya David mungkin menyukai sesuatu.
Jack M.
kemungkinan duplikat serializer Django untuk satu objek
sleepycal

Jawaban:

242

Anda dapat dengan mudah menggunakan daftar untuk membungkus objek yang diperlukan dan itu semua yang diperlukan serializer django untuk membuat serialisasi dengan benar, misalnya .:

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])
xaralis
sumber
9
Tetapi sebagai tanggapan Anda diminta untuk mengindeks elemen nol dari objek JSON untuk sampai ke objek serial. Hanya sesuatu yang perlu diperhatikan.
Davor Lucic
10
Dan bagaimana dengan membuat serial semua objek yang direferensikan bersama dengan objek root?
paweloque
1
Apakah Anda tidak ingin [0]di akhir baris terakhir Anda, seperti yang disarankan @DavorLucic? Dan tidak perlu untuk mengikuti koma dalam daftar Anda secara literal (untuk cinta PEP8;).
hobs
Deserialisasi juga membutuhkan langkah ekstra; lihat stackoverflow.com/a/29550004/2800876
Zags
5
Ini tidak berhasil untuk saya. Django melempar objek 'tuple' AttributeError tidak memiliki atribut '_meta'
adamF
71

Jika Anda berurusan dengan daftar contoh model yang terbaik yang dapat Anda lakukan adalah menggunakannya serializers.serialize(), itu akan sesuai dengan kebutuhan Anda dengan sempurna.

Namun, Anda harus menghadapi masalah dengan mencoba membuat serialisasi objek tunggal , bukan listobjek. Dengan begitu, untuk menyingkirkan hack yang berbeda, gunakan saja Django model_to_dict(jika saya tidak salah, serializers.serialize()andalkan juga):

from django.forms.models import model_to_dict

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

Anda sekarang hanya perlu satu json.dumpspanggilan langsung untuk membuat serial menjadi json:

import json
serialized = json.dumps(dict_obj)

Itu dia! :)

Pavel Daynyak
sumber
6
ini gagal dengan bidang UUID, harus jelas jika tidak
Alvin
2
gagal dengan datetimebidang. Dipecahkan dengan cara ini json.loads(serialize('json', [obj]))[0]sementara serializer adalahdjango.core.serializers.serialize
Lal Zada
43

Untuk menghindari pembungkus array, hapus sebelum Anda mengembalikan respons:

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')

Saya menemukan posting yang menarik ini pada subjek juga:

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

Ini menggunakan django.forms.models.model_to_dict, yang terlihat seperti alat yang sempurna untuk pekerjaan itu.

Julian
sumber
9
jika ini adalah cara terbaik untuk membuat serial model tunggal dalam Django, maka itu mengerikan karena kita tidak perlu membatalkan deserialisasi json dan membuat serial kembali.
Herbert
@Herbert, mungkin. Tapi begitulah. Jika Anda memiliki cara yang lebih baik, saya semua telinga. Ini seharusnya tidak memiliki banyak kelemahan praktis karena mengambil dan menghapus / meng-encode objek tunggal seharusnya tidak menghabiskan banyak sumber daya. Jadikan itu menjadi fungsi pembantu atau memperluas / mencampur dengan objek Anda sebagai metode baru jika Anda ingin menyembunyikan horor.
Julian
1
Menyembunyikan kengerian bukanlah masalah dan mungkin bahkan bukan solusi ini; apa yang mengejutkan saya adalah bahwa ini adalah cara terbaik Django untuk melakukannya.
Herbert
14

Ada jawaban yang bagus untuk ini dan saya terkejut belum disebutkan. Dengan beberapa baris Anda dapat menangani tanggal, model, dan yang lainnya.

Buat pembuat enkode khusus yang dapat menangani model:

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)

Sekarang gunakan saat Anda menggunakan json.dumps

json.dumps(data, cls=ExtendedEncoder)

Sekarang model, tanggal dan semuanya dapat diserialisasi dan tidak harus dalam array atau serial dan tidak di-serial. Apa pun yang Anda miliki yang dapat ditambahkan hanya dapat ditambahkan kedefault metode.

Anda bahkan dapat menggunakan JsonResponse asli Django dengan cara ini:

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)
``
kagronick
sumber
3
Solusi ini sederhana dan elegan. Encoder dapat digunakan dengan metode json.dumpsdan keduanya json.dump. Dengan cara ini Anda tidak perlu mengubah alur kerja aplikasi karena Anda menggunakan objek khusus atau menambahkan pemanggilan metode lain sebelum mengonversi ke json. Cukup tambahkan kode konversi Anda di enkoder dan Anda siap berangkat.
Claudiu
11

Kedengarannya seperti apa yang Anda tanyakan melibatkan serialisasi struktur data model Django misalnya untuk interoperabilitas. Poster-poster lain benar: jika Anda ingin formulir berseri untuk digunakan dengan aplikasi python yang dapat meminta basis data melalui api Django, maka Anda akan ingin membuat cerita bersambung sebuah queryset dengan satu objek. Jika, di sisi lain, apa yang Anda butuhkan adalah cara untuk kembali mengembang contoh model di tempat lain tanpa menyentuh database atau tanpa menggunakan Django, maka Anda memiliki sedikit pekerjaan yang harus dilakukan.

Inilah yang saya lakukan:

Pertama, saya gunakan demjson untuk konversi. Kebetulan itulah yang saya temukan pertama kali, tetapi mungkin bukan yang terbaik. Implementasi saya tergantung pada salah satu fiturnya, tetapi harus ada cara yang serupa dengan konverter lainnya.

Kedua, terapkan json_equivalentmetode pada semua model yang mungkin Anda perlukan serial. Ini adalah metode ajaib demjson, tetapi ini mungkin sesuatu yang ingin Anda pikirkan terlepas dari penerapan apa yang Anda pilih. Idenya adalah Anda mengembalikan objek yang dapat langsung dikonversi json(yaitu array atau kamus). Jika Anda benar-benar ingin melakukan ini secara otomatis:

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

Ini tidak akan membantu Anda kecuali Anda memiliki struktur data yang benar-benar datar (tidak ForeignKeys , hanya angka dan string dalam database, dll.). Jika tidak, Anda harus dengan serius memikirkan cara yang tepat untuk menerapkan metode ini.

Ketiga, telepon demjson.JSON.encode(instance)dan Anda memiliki apa yang Anda inginkan.

David Berger
sumber
Saya belum mencoba kode itu tetapi saya hanya ingin menunjukkan beberapa kesalahan di dalamnya. Ini adalah instance._meta.get_all_field_names () dan getattribute adalah fungsi jadi seharusnya () dan bukan [].
Jason Christa
sebagai tambahan untuk FK, ini tidak akan bekerja untuk bidang datetime (kecuali ada sihir di demjson.JSON.encode)
Skylar Saveland
8

Jika Anda bertanya bagaimana membuat serial objek tunggal dari model dan Anda tahu Anda hanya akan mendapatkan satu objek di queryset (misalnya, menggunakan objek.get), kemudian gunakan sesuatu seperti:

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")

yang akan memberi Anda sesuatu berupa:

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}
Benlast
sumber
Tapi itu akan menghapus semua tanda kurung siku, bukan hanya yang luar. Lebih baik? "o = s [1: -1]"?
Julian
5

Saya memecahkan masalah ini dengan menambahkan metode serialisasi ke model saya:

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

Berikut ini adalah padanan verbose bagi mereka yang menolak untuk satu kalimat:

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 adalah daftar bidang model yang dipesan yang dapat diakses dari instance dan dari model itu sendiri.

davidchambers
sumber
3
Meskipun ide itu mungkin tampak bagus pada awalnya, orang harus menunjukkan bahwa ada konsekuensi untuk menggunakan pendekatan ini. Anda mengikat satu keluaran serialisasi tertentu ke model Anda.
Jonas Geiregat
@JonasGeiregat karena metode ini didefinisikan berdasarkan model-ke-model, apa yang salah dengan pendekatannya? Sayangnya ini tampaknya menjadi satu-satunya cara untuk mengembalikan objek json yang berisi bidang dan kunci utama instance.
dopatraman
5

Inilah solusi saya untuk ini, yang memungkinkan Anda untuk dengan mudah menyesuaikan JSON serta mengatur catatan terkait

Pertama menerapkan metode pada model. Saya menelepon jsontetapi Anda bisa menyebutnya apa pun yang Anda suka, misalnya:

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

Maka dalam tampilan saya lakukan:

data = [car.json for car in Car.objects.all()]
return HttpResponse(json.dumps(data), content_type='application/json; charset=UTF-8', status=status)
DanH
sumber
Dalam Python 3, itu menjadicar.json()
T.Coutlakis
4

Gunakan daftar, itu akan menyelesaikan masalah

Langkah 1:

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

Langkah 2:

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

Step3:

 return HttpResponse(json.dumps(result), content_type = "application/json")
niran
sumber
Ini sepertinya masih bersambung sebagai json array (objek) bukan objek telanjang, yang ditanyakan OP. iow, ini tidak berbeda dari metode serialisasi biasa.
Julian
1
Ini akan gagal dengan kesalahan serialisasi JSON. Objek queryset tidak bersambung
dopatraman
4

Untuk membuat serial dan deserialze, gunakan yang berikut ini:

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
Zags
sumber
Saya mendapatkan 'objek generator tidak memiliki atribut' berikutnya '. Ada ide?
user2880391
1
@ user2880391 Saya telah memperbarui ini untuk Python 3. Apakah itu memperbaikinya?
Zags
4

.values() adalah apa yang saya butuhkan untuk mengonversi contoh model ke JSON.

dokumentasi .values ​​(): https://docs.djangoproject.com/en/3.0/ref/models/querysets/#values

Contoh penggunaan dengan model yang disebut Project .

Catatan: Saya menggunakan 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])

Hasil dari id yang valid:

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

Jika Anda ingin mengembalikan objek model tunggal sebagai respons json ke klien, Anda dapat melakukan solusi sederhana ini:

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))
flowfelis
sumber
2

Gunakan Django Serializer dengan pythonformat,

from django.core import serializers

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

Apa perbedaan antara jsondanpython format?

The jsonFormat akan kembali hasil sebagai strsedangkan pythonakan kembali hasilnya baik listatauOrderedDict

JPG
sumber
itu sangat disayangkan
JPG
Saya dapatkan OrderedDict, tidakdict
user66081
1

Tampaknya Anda tidak bisa membuat serial suatu instance, Anda harus membuat serial suatu QuerySet dari satu objek.

from django.core import serializers
from models import *

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

Saya kehabisan svnrilis Django, jadi ini mungkin tidak ada di versi sebelumnya.

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

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

Saya kembalikan contoh saya

jadi itu mengembalikan sesuatu seperti {'field1': value, "field2": value, ....}


sumber
ini akan mematahkan:TypeError: <django.db.models.base.ModelState object at 0x7f2b3bf62310> is not JSON serializable
Julio Marins
1

bagaimana dengan cara ini:

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

atau mengecualikan apa pun yang tidak Anda inginkan.

Reorx
sumber
0

Semua jawaban ini sedikit berantakan dibandingkan dengan apa yang saya harapkan dari suatu kerangka kerja, metode paling sederhana, saya pikir sejauh ini, jika Anda menggunakan kerangka kerja sisanya:

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

Ini menggunakan Serializer secara langsung, menghormati bidang yang telah Anda tentukan, serta asosiasi apa pun, dll.

iantbutler
sumber