Django'da bir model örneğini nasıl serileştirirsiniz?


159

Bir Model Sorgu Kümesinin nasıl serileştirileceğine dair birçok belge vardır, ancak bir Model Eşgörünümünün alanlarını JSON'a nasıl serileştirirsiniz?


1 nesnenin bir sorgu kümesini serileştirebildiğiniz halde, bunu django.coreyapmak için sınıfları kullanamazsınız . Queryset'i serileştirmemek için özel bir neden var mı?
Jack

1
Queryset serileştirici, sonucu olması gerekenden iki kat daha fazla sarar. Bu yüzden data.name yerine data [0] .fields.name yapmalısınız.
Jason Christa

Bende böyle düşünmüştüm. Django arka uç için bir GWT arayüzü yazarken aynı sorunla karşılaştım. Görünüşe göre David bir şeyin üzerinde olabilir.
Jack

Yanıtlar:


242

Gerekli nesneyi sarmak için bir listeyi kolayca kullanabilirsiniz ve django serileştiricilerinin doğru şekilde serileştirmesi için gereken şey budur, örn .:

from django.core import serializers

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

9
Ancak yanıt olarak, serileştirilmiş nesneye ulaşmak için JSON nesnesinin sıfır öğesini dizinlemeniz gerekir. Dikkat edilmesi gereken bir şey.
Davor Lucic

10
Ve referans alınan tüm nesneleri kök nesne ile birlikte serileştirmeye ne dersiniz?
paweloque

1
[0]@DavorLucic tarafından önerilen gibi son satırınızın sonunda istemiyor musunuz ? Ve liste hazırlığında virgül izlemeye gerek yok (PEP8 sevgisi için;).
Ocaklar

Serileştirme ayrıca bir adım daha gerektirir; bkz. stackoverflow.com/a/29550004/2800876
Zags

5
Bu benim için işe yaramadı. Django AttributeError 'tuple' nesnesinin '_meta' niteliğine sahip değil
adamF

71

Yapabileceğiniz en iyi model örneklerinin bir listesi ile uğraşıyorsanız serializers.serialize(), ihtiyacınıza mükemmel bir şekilde uyacaktır.

Ancak, nesnelerin değil, tek bir nesnenin serileştirilmesiyle ilgili bir sorunla karşılaşacaksınız list. Bu şekilde, farklı saldırılardan kurtulmak için sadece Django'ları kullanın model_to_dict(yanılmıyorsam serializers.serialize()da buna güvenir):

from django.forms.models import model_to_dict

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

Şimdi json.dumpsjson'a serileştirmek için tek bir düz çağrıya ihtiyacınız var :

import json
serialized = json.dumps(dict_obj)

Bu kadar! :)


6
bu UUID alanları ile başarısız, aksi takdirde açık olmalıdır
Alvin

2
datetimealanlarla başarısız . json.loads(serialize('json', [obj]))[0]Serileştirici iken bu şekilde çözüldüdjango.core.serializers.serialize
Lal Zada

43

Dizi sarmalayıcıyı önlemek için yanıtı döndürmeden önce kaldırın.

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

Bu konuda da ilginç bir yazı buldum:

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

İş için mükemmel bir araç gibi görünen django.forms.models.model_to_dict kullanır.


9
Bu, django'da tek bir modeli serileştirmenin en iyi yoluysa, bu json'un serisini kaldırması ve serileştirmesi gerekmediği için korkunçtur.
Herbert

@Herbert, belki. Ama işte burada. Eğer daha iyi bir yolun varsa, ben kulaklarım. Tek bir nesnenin getirilmesi ve kodunun çözülmesi o kadar kaynak harcamaması gerektiğinden, bunun pratik bir dezavantajı olmamalıdır. Korkuyu gizlemek istiyorsanız, yardımcı bir işlev haline getirin veya nesnelerinizle yeni bir yöntem olarak genişletin / karıştırın.
Julian

1
Korkuyu gizlemek sorun değildir ve belki de bu çözüm değildir; beni şaşırtan şey django'nun bunu yapmanın en iyi yoludur.
Herbert

14

Bunun iyi bir cevabı var ve bundan bahsedilmediğine şaşırdım. Birkaç satırla tarihleri, modelleri ve diğer her şeyi işleyebilirsiniz.

Modelleri işleyebilen özel bir kodlayıcı oluşturun:

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)

Şimdi json.dumps kullanırken kullanın

json.dumps(data, cls=ExtendedEncoder)

Artık modeller, tarihler ve her şey serileştirilebilir ve bir dizide veya serileştirilmiş ve serileştirilmiş olması gerekmez. Özel olan herhangi bir şey sadece defaultyönteme eklenebilir .

Django'nun yerel JsonResponse'sini şu şekilde bile kullanabilirsiniz:

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)
``

3
Bu çözüm basit ve zariftir. Kodlayıcı hem json.dumpsve json.dumpyöntemlerle kullanılabilir. Bu şekilde, özel nesneler kullandığınız veya json'a dönüştürmeden önce başka bir yöntem çağrısı eklediğiniz için uygulamanın iş akışını değiştirmeniz gerekmez. Dönüşüm kodunuzu kodlayıcıya eklemeniz yeterlidir.
Claudiu

11

Sorduğunuz şey, birlikte çalışabilirlik için bir Django model örneğinin veri yapısını serileştirmeyi içeriyor gibi görünüyor. Diğer posterler doğrudur: serileştirilmiş formun veritabanını Django'nun api'si üzerinden sorgulayabilen bir python uygulamasıyla kullanılmasını istiyorsanız, bir sorgu kümesini tek bir nesne ile serileştirmek istersiniz. Öte yandan, ihtiyacınız olan şey model örneğini veritabanına dokunmadan veya Django kullanmadan başka bir yere yeniden şişirmenin bir yoluysa, yapmak için biraz işiniz var.

İşte yaptığım şey:

İlk olarak, demjsondönüşüm için kullanıyorum . İlk bulduğum şey oldu, ama en iyisi olmayabilir. Uygulamam özelliklerinden birine bağlı, ancak diğer dönüştürücülerle benzer yollar olmalı.

İkinci olarak, json_equivalentserileştirmeniz gerekebilecek tüm modellere bir yöntem uygulayın. Bu sihirli bir yöntem demjson, ancak hangi uygulamayı seçerseniz seçin muhtemelen düşünmek isteyeceğiniz bir şey. Fikir, doğrudan dönüştürülebilen bir nesneyi json(yani bir dizi veya sözlük) döndürmenizdir . Bunu gerçekten otomatik olarak yapmak istiyorsanız:

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

Tamamen düz bir veri yapınız yoksa (hayır ForeignKeys, yalnızca veritabanındaki sayılar ve dizeler vb.) Bu size yardımcı olmayacaktır . Aksi takdirde, bu yöntemi uygulamak için doğru yolu ciddi bir şekilde düşünmelisiniz.

Üçüncü olarak, arayın demjson.JSON.encode(instance)ve istediğiniz her şeye sahipsiniz.


Henüz kodu denemedim ama sadece bazı hataları işaret etmek istedim. İnstance._meta.get_all_field_names () ve getattribute , [] değil, () olması gereken bir işlevdir.
Jason Christa

FK'ye ek olarak, bu datetime alanları için çalışmaz (demjson.JSON.encode içinde sihir yoksa)
Skylar Saveland

8

Bir modelden tek bir nesnenin nasıl serileştirileceğini soruyorsanız ve sorgu kümesinde yalnızca bir nesne alacağınızı biliyorsanız (örneğin, objects.get kullanarak), o zaman şöyle bir şey kullanın:

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

size şu biçimden bir şey getirir:

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

Ama bu sadece dış köşeleri değil, tüm köşeli parantezleri de kesecek. Daha iyi? "o = s [1: -1]"?
Julian

5

Modelime bir serileştirme yöntemi ekleyerek bu sorunu çözdüm:

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

İşte bir astardan uzak olanlar için ayrıntılı eşdeğer:

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 örneklerden ve modelin kendisinden erişilebilen sıralı bir model alanları listesidir.


3
Fikir ilk başta iyi görünse de, bu yaklaşımı kullanmanın sonuçları olduğu belirtilmelidir. Modelinize belirli bir serileştirme çıkışı bağlıyorsunuz.
Jonas Geiregat

@JonasGeiregat bu yöntem model-model bazında tanımlandığından, yaklaşımda sorun nedir? Ne yazık ki bu, hem alanları hem de örneğin birincil anahtarını içeren bir json nesnesini döndürmenin tek yolu gibi görünüyor.
dopatraman

5

İşte bunun için JSON'u kolayca özelleştirmenize ve ilgili kayıtları düzenlemenize izin veren çözümüm

İlk olarak model üzerinde bir yöntem uygulayın. Ben çağırıyorum jsonama ne istersen arayabilirsiniz, örneğin:

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

Sonra görüşte:

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'te bucar.json()
T.Coutlakis

4

Kullanım listesi, sorunu çözecektir

Aşama 1:

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

Adım 2:

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

Aşama 3:

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

Bu hala OP'nin sorduğu çıplak bir nesne değil, bir json dizisi (nesnelerin) olarak serileştirilecek gibi görünüyor. iow, bu normal serileştirme yönteminden farklı değildir.
Julian

1
Bu bir JSON serileştirme hatasıyla başarısız olur. Queryset nesneleri serileştirilemez
dopatraman

4

Serileştirmek ve serisini kaldırmak için aşağıdakileri kullanın:

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

'Jeneratör nesnesinin' next 'özelliği yok. Herhangi bir fikir?
user2880391

1
@ user2880391 Bunu Python 3 için güncelledim. Bu sorunu çözüyor mu?
Zags

4

.values() bir model örneği JSON dönüştürmek için gereken budur.

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

Project adlı bir modelle örnek kullanım .

Not: Django Rest Framework kullanıyorum

    @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])

Geçerli bir kimlikten sonuç:

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

3

Tek model nesnesini bir istemciye json yanıtı olarak döndürmek istiyorsanız, bu basit çözümü yapabilirsiniz:

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

Kullanın Django Serializer ile pythonformatında,

from django.core import serializers

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

Arasındaki fark nedir jsonvepython format ?

jsonOlarak biçim sonuç döndürür striken, pythoniçinde bir sonuç döndürür ya listveyaOrderedDict


bu çok talihsiz
JPG

Anladım OrderedDict, değildict
user66081

1

Bir örneği serileştirebileceğiniz görülmüyor, bir nesnenin Sorgu Kümesini serileştirmeniz gerekir.

from django.core import serializers
from models import *

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

Ben svndjango sürümü bitti , bu yüzden bu önceki sürümlerinde olmayabilir.


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

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

Örneğimin kararını geri veriyorum

bu yüzden {'field1': değer, "field2": değer, ....} gibi bir şey döndürür


Bu kırılacak:TypeError: <django.db.models.base.ModelState object at 0x7f2b3bf62310> is not JSON serializable
Julio Marins

1

bu şekilde:

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

veya istemediğiniz herhangi bir şeyi hariç tutun.


0

Tüm bu cevaplar, bir çerçeve, en basit yöntemden beklediğim ile karşılaştırıldığında biraz acayipti, sanırım geri kalan çerçeveyi kullanıyorsanız:

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

Bu, üzerinde tanımladığınız alanlara ve ilişkilendirmelere vb. Saygı duyarak doğrudan Serializer'ı kullanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.