Google अनुप्रयोग इंजन मॉडल का JSON क्रमांकन


86

मैं काफी समय से बिना किसी सफलता के खोज रहा हूं। मेरा प्रोजेक्ट Django का उपयोग नहीं कर रहा है, क्या JSON में ऐप इंजन मॉडल (google.appengine.ext.db.Model) को अनुक्रमित करने का एक सरल तरीका है या क्या मुझे अपना खुद का सीरियल लिखने की आवश्यकता है?

नमूना:

class Photo(db.Model):
    filename = db.StringProperty()
    title = db.StringProperty()
    description = db.StringProperty(multiline=True)
    date_taken = db.DateTimeProperty()
    date_uploaded = db.DateTimeProperty(auto_now_add=True)
    album = db.ReferenceProperty(Album, collection_name='photo')

जवाबों:


62

एक साधारण पुनरावर्ती फ़ंक्शन का उपयोग एक इकाई (और किसी भी संदर्भ) को एक नेस्टेड शब्दकोश में परिवर्तित करने के लिए किया जा सकता है जिसे पास किया जा सकता है simplejson:

import datetime
import time

SIMPLE_TYPES = (int, long, float, bool, dict, basestring, list)

def to_dict(model):
    output = {}

    for key, prop in model.properties().iteritems():
        value = getattr(model, key)

        if value is None or isinstance(value, SIMPLE_TYPES):
            output[key] = value
        elif isinstance(value, datetime.date):
            # Convert date/datetime to MILLISECONDS-since-epoch (JS "new Date()").
            ms = time.mktime(value.utctimetuple()) * 1000
            ms += getattr(value, 'microseconds', 0) / 1000
            output[key] = int(ms)
        elif isinstance(value, db.GeoPt):
            output[key] = {'lat': value.lat, 'lon': value.lon}
        elif isinstance(value, db.Model):
            output[key] = to_dict(value)
        else:
            raise ValueError('cannot encode ' + repr(prop))

    return output

2
कोड में एक छोटी सी गलती है: जहां आपके पास "आउटपुट [कुंजी] = to_dict (मॉडल)" यह होना चाहिए: "आउटपुट [कुंजी] = to_dict (मान)"। इसके अलावा यह एकदम सही है। धन्यवाद!
एरिकफ्रेंड

1
यह कोड विफल हो जाएगा जब यह एक UserProperty का सामना करता है। मैंने इसे अंतिम रूप से "आउटपुट [कुंजी] = str (मूल्य)" के साथ अंतिम रूप से त्रुटि करने के बजाय काम करने के साथ काम किया।
बोरिस टेरिक

1
उत्तम सामग्री। छोटे सुधार के बजाय iterkeys () का उपयोग करना है क्योंकि आप "प्रोप" का उपयोग नहीं करते हैं।
PEZ

7
मैंने सभी संभावित प्रकारों (दिनांक, GeoPt, ...) की कोशिश नहीं की है, लेकिन ऐसा लगता है कि डेटास्टोर के पास वास्तव में यह विधि है, और यह मेरे लिए अब तक तार और पूर्णांक के लिए काम कर रहा है: Developers.google.com/appengine/ डॉक्स / पाइथन / डेटास्टोर /… तो मुझे यकीन नहीं है कि आपको json.dumps(db.to_dict(Photo))
जीसस को सिलसिलेवार

@gentimouton यह विधि एक नया जोड़ है। यह निश्चित रूप से 2009 में मौजूद नहीं था
dmw

60

यह सबसे सरल उपाय है जो मैंने पाया। इसके लिए केवल 3 लाइनों के कोड की आवश्यकता होती है।

शब्दकोश को वापस करने के लिए अपने मॉडल में एक विधि जोड़ें:

class DictModel(db.Model):
    def to_dict(self):
       return dict([(p, unicode(getattr(self, p))) for p in self.properties()])

SimpleJSON अब ठीक से काम करता है:

class Photo(DictModel):
   filename = db.StringProperty()
   title = db.StringProperty()
   description = db.StringProperty(multiline=True)
   date_taken = db.DateTimeProperty()
   date_uploaded = db.DateTimeProperty(auto_now_add=True)
   album = db.ReferenceProperty(Album, collection_name='photo')

from django.utils import simplejson
from google.appengine.ext import webapp

class PhotoHandler(webapp.RequestHandler):
   def get(self):
      photos = Photo.all()
      self.response.out.write(simplejson.dumps([p.to_dict() for p in photos]))

टिप के लिए धन्यवाद। यह बहुत अच्छा काम करता है, सिवाय इसके कि मैं दिनांक क्षेत्र को क्रमबद्ध नहीं कर सकता। मुझे मिलता है: TypeError: datetime.datetime (2010, 5, 1, 9, 25, 22, 891937) JSON
अनुक्रमिक

नमस्ते, इस मुद्दे को इंगित करने के लिए धन्यवाद। समाधान दिनांक ऑब्जेक्ट को स्ट्रिंग में परिवर्तित करना है। उदाहरण के लिए, आप कॉल को "यूनिकोड ()" के साथ "गेटैट (स्वयं, पी)" में लपेट सकते हैं। मैंने इसे दर्शाने के लिए कोड संपादित किया।
सुबह 10:07

1
Dict ([(पी, यूनिकोड (getattr (स्वयं, पी))) self.properties में पी (के लिए) नहीं तो p.startswith ( "_")]): db.Model के मेटा क्षेत्रों को निकालने के लिए इस का उपयोग
Wonil

ndb के लिए, fredva का उत्तर देखें।
केंजी नोगुची

self.properties () मेरे लिए काम नहीं किया। मैंने स्वयं का उपयोग किया। पूर्ण पंक्ति: स्वंय में पी के लिए वापस तानाशाह ([(पी, यूनिकोड (गेटेट्र (सेल्फ), पी)))
लेविन

15

ऐप इंजन एसडीके के नवीनतम (1.5.2) रिलीज़ में, एक to_dict()फ़ंक्शन जो मॉडल उदाहरणों को शब्दकोशों में परिवर्तित करता है , में पेश किया गया था db.pyजारी नोट देखें ।

इस फ़ंक्शन का अभी तक दस्तावेज़ में कोई संदर्भ नहीं है, लेकिन मैंने इसे स्वयं आज़माया है और यह अपेक्षा के अनुरूप काम करता है।


मुझे आश्चर्य है कि अगर इसे हटा दिया गया है? मुझे AttributeError: 'module' object has no attribute 'to_dict'तब मिलता है जब मैं from google.appengine.ext import dbऔर उपयोग करता हूं simplejson.dumps(db.to_dict(r))(जहां r एक db.Model उपवर्ग का एक उदाहरण है)। मैं google_appengine / google / appengine / ext / db / * में "to_dict" नहीं देखता
idbrii

1
इसे "db.to_dict (ObjectOfClassModel)" की तरह इस्तेमाल किया जाना है
दिमित्री

2
ndb ऑब्जेक्ट के लिए, self.to_dict () काम करता है। यदि आप मानक जोंस मॉड्यूल द्वारा वर्ग को क्रमबद्ध बनाना चाहते हैं, तो 'डिफॉल्ट डिफॉल्ट (सेल्फ, ओ): रिटर्न ओ.टो_डक्ट ()' को क्लास में जोड़ें
नोगुची

7

मॉडल को क्रमबद्ध करने के लिए, निम्नलिखित अजगर के रूप में एक कस्टम जोंस एनकोडर जोड़ें:

import datetime
from google.appengine.api import users
from google.appengine.ext import db
from django.utils import simplejson

class jsonEncoder(simplejson.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()

        elif isinstance(obj, db.Model):
            return dict((p, getattr(obj, p)) 
                        for p in obj.properties())

        elif isinstance(obj, users.User):
            return obj.email()

        else:
            return simplejson.JSONEncoder.default(self, obj)


# use the encoder as: 
simplejson.dumps(model, cls=jsonEncoder)

यह सांकेतिक शब्दों में बदलना होगा:

  • isoformat स्ट्रिंग के रूप में एक तारीख ( इस सुझाव के अनुसार) ),
  • एक मॉडल अपने गुणों के एक तानाशाह के रूप में,
  • एक उपयोगकर्ता अपने ईमेल के रूप में।

दिनांक का उपयोग करने के लिए आप इस जावास्क्रिप्ट का उपयोग कर सकते हैं:

function decodeJsonDate(s){
  return new Date( s.slice(0,19).replace('T',' ') + ' GMT' );
} // Note that this function truncates milliseconds.

नोट: उपयोगकर्ता pydave का धन्यवाद जिन्होंने इसे और अधिक पठनीय बनाने के लिए इस कोड को संपादित किया। मैंने मूल रूप से अजगर की if / if अभिव्यक्तियों को jsonEncoderनिम्न पंक्तियों में व्यक्त करने के लिए उपयोग किया था : (मैंने कुछ टिप्पणियाँ जोड़ी हैं और इसका इस्तेमाल किया है google.appengine.ext.db.to_dict, इसे मूल से अधिक स्पष्ट बनाने के लिए।)

class jsonEncoder(simplejson.JSONEncoder):
  def default(self, obj):
    isa=lambda x: isinstance(obj, x) # isa(<type>)==True if obj is of type <type>
    return obj.isoformat() if isa(datetime.datetime) else \
           db.to_dict(obj) if isa(db.Model) else \
           obj.email()     if isa(users.User) else \
           simplejson.JSONEncoder.default(self, obj)

4

आपको अपना "पार्सर" लिखने की ज़रूरत नहीं है (एक पार्सर संभवतः जेन्सन को पायथन ऑब्जेक्ट में बदल देगा), लेकिन आप अभी भी अपने पायथन ऑब्जेक्ट को स्वयं सीरियल कर सकते हैं।

Simplejson का उपयोग करना :

import simplejson as json
serialized = json.dumps({
    'filename': self.filename,
    'title': self.title,
    'date_taken': date_taken.isoformat(),
    # etc.
})

1
हां, लेकिन मैं हर मॉडल के लिए ऐसा नहीं करना चाहता। मैं एक स्केलेबल दृष्टिकोण खोजने की कोशिश कर रहा हूं।
user111677

ओह और मैं वास्तव में हैरान हूं कि मुझे इस पर कोई सर्वोत्तम अभ्यास नहीं मिल रहा है। मैंने सोचा था कि ऐप इंजन मॉडल + rpc + json एक दिया गया था ...
14:11 पर user111677

4

साधारण मामलों के लिए, मुझे लेख के अंत में यहाँ दिए गए दृष्टिकोण की तरह :

  # after obtaining a list of entities in some way, e.g.:
  user = users.get_current_user().email().lower();
  col = models.Entity.gql('WHERE user=:1',user).fetch(300, 0)

  # ...you can make a json serialization of name/key pairs as follows:
  json = simplejson.dumps(col, default=lambda o: {o.name :str(o.key())})

लेख में स्पेक्ट्रम के दूसरे छोर पर एक जटिल धारावाहिक वर्ग भी शामिल है, जो _metaडीजेंगो को समृद्ध करता है (और इसकी आवश्यकता नहीं है - आपको यह याद नहीं है कि आप _meta के बारे में गलतियां क्यों कर रहे हैं, शायद यहां वर्णित बग ) कम्प्यूटरीकृत अनुक्रमित करने की क्षमता के साथ। गुण / विधियाँ। ज्यादातर समय जब आप क्रमबद्धता की जरूरत होती है, तो बीच में कहीं और ले सकते हैं, और उन लोगों के लिए, जैसे @David विल्सन के लिए एक आत्मनिरीक्षण दृष्टिकोण।


3

भले ही आप django को एक फ्रेमवर्क के रूप में उपयोग नहीं कर रहे हैं, फिर भी वे लाइब्रेरीज़ आपके उपयोग के लिए उपलब्ध हैं।

from django.core import serializers
data = serializers.serialize("xml", Photo.objects.all())

क्या आपका मतलब था serializers.serialize ("json", ...)? वह "AttrearError: 'Photo' ऑब्जेक्ट को कोई विशेषता नहीं देता है '_meta'"। FYI करें - serializers.serialize ("xml", Photo.objects.all ()) "AttributeError: type object 'Photo' में कोई विशेषता 'ऑब्जेक्ट' नहीं है।" serializers.serialize ("xml", Photo.all ()) "SerializationError: गैर-मॉडल ऑब्जेक्ट (<वर्ग 'मॉडल.Photo>>) क्रमांकन के दौरान सामने आया।
user111677

2

यदि आप ऐप-इंजन-पैच का उपयोग करते हैं तो यह स्वचालित रूप से _metaआपके लिए विशेषता घोषित करेगा , और फिर आप उपयोग कर सकते हैंdjango.core.serializers जैसा कि आप सामान्य रूप से django मॉडल पर करते हैं (जैसा कि स्लेज के कोड में)।

ऐप-इंजन-पैच में कुछ अन्य शांत विशेषताएं हैं जैसे कि एक हाइब्रिड प्रमाणीकरण (django + Google खाते) हैं, और dango सेवाओं का व्यवस्थापक भाग है।


ऐप-इंजन-पैच बनाम google-app-engine-django बनाम ऐप इंजन python sdk के साथ भेजे गए django वर्जन में क्या अंतर है? जो मैं समझता हूं, ऐप-इंजन-पैच अधिक पूर्ण है?
user111677

मैंने ऐप इंजन पर django के संस्करण की कोशिश नहीं की है, लेकिन मुझे लगता है कि यह एकीकृत है। अगर मैं गलत नहीं हूँ तो google-app-engine-django ऐप-इंजन (कुछ सीमाओं के साथ) के साथ django के मॉडल को बनाने की कोशिश करता है। ऐप-इंजन-पैच सीधे ऐप-इंजन मॉडल का उपयोग करता है, वे बस इसमें कुछ नाबालिग सामान जोड़ते हैं। उनकी वेबसाइट पर दोनों के बीच तुलना है।
मटौरने

2

माउंटग्रेटेड के ऊपर दिए गए जवाब ने मेरे लिए अद्भुत काम किया - मैंने इसे थोड़ा संशोधित किया ताकि मुझे प्रवेश के लिए भी कुंजी मिल सके। कोड की कुछ पंक्तियों के रूप में नहीं, लेकिन यह मुझे अद्वितीय कुंजी देता है:

class DictModel(db.Model):
def to_dict(self):
    tempdict1 = dict([(p, unicode(getattr(self, p))) for p in self.properties()])
    tempdict2 = {'key':unicode(self.key())}
    tempdict1.update(tempdict2)
    return tempdict1

2

मैंने समर्थन के लिए dpatru द्वारा लिखित JSON एनकोडर वर्ग बढ़ाया है :

  • क्वेरी परिणाम गुण (जैसे car.owner_set)
  • ReferenceProperty - इसे पुन: JSON में बदल दें
  • फ़िल्टरिंग गुण - केवल एक verbose_nameइच्छा वाले गुणों को JSON में एन्कोड किया जाएगा

    class DBModelJSONEncoder(json.JSONEncoder):
        """Encodes a db.Model into JSON"""
    
        def default(self, obj):
            if (isinstance(obj, db.Query)):
                # It's a reference query (holding several model instances)
                return [self.default(item) for item in obj]
    
            elif (isinstance(obj, db.Model)):
                # Only properties with a verbose name will be displayed in the JSON output
                properties = obj.properties()
                filtered_properties = filter(lambda p: properties[p].verbose_name != None, properties)
    
                # Turn each property of the DB model into a JSON-serializeable entity
                json_dict = dict([(
                        p,
                        getattr(obj, p)
                            if (not isinstance(getattr(obj, p), db.Model))
                            else
                        self.default(getattr(obj, p)) # A referenced model property
                    ) for p in filtered_properties])
    
                json_dict['id'] = obj.key().id() # Add the model instance's ID (optional - delete this if you do not use it)
    
                return json_dict
    
            else:
                # Use original JSON encoding
                return json.JSONEncoder.default(self, obj)
    

2

जैसा कि https://stackoverflow.com/users/806432/fredva द्वारा बताया गया है , to_dict बहुत अच्छा काम करता है। यहाँ मेरे कोड का उपयोग कर रहा हूँ।

foos = query.fetch(10)
prepJson = []

for f in foos:
  prepJson.append(db.to_dict(f))

myJson = json.dumps(prepJson))

हां, और मॉडल पर एक "to_dict" भी है ... यह फ़ंक्शन इस पूरी समस्या को उतना ही तुच्छ बनाने की कुंजी है जितना इसे होना चाहिए। यह भी "संरचित" और "दोहराया" गुणों के साथ NDB के लिए काम करता है!
निक पर्किंस

1

सभी मॉडल वर्गों के लिए परिभाषित एक विधि, "Model.properties ()" है। यह आपके द्वारा चाहा गया हुक्म लौटाता है।

from django.utils import simplejson
class Photo(db.Model):
  # ...

my_photo = Photo(...)
simplejson.dumps(my_photo.properties())

डॉक्स में मॉडल गुण देखें ।


कुछ वस्तुएं "JSON TypeError: <google.appengine.ext.db.StringProperty object at 0x4694550> is not JSON serializable
अनुक्रमिक

1

ये API (google.appengine.ext.db) अब अनुशंसित नहीं हैं। इन API का उपयोग करने वाले ऐप्स केवल App Engine Python 2 रनटाइम में चल सकते हैं और App Engine Python 3 रनटाइम पर माइग्रेट होने से पहले अन्य API और सेवाओं में माइग्रेट करने की आवश्यकता होगी। अधिक जानने के लिए: यहां क्लिक करें


0

डेटास्टोर मॉडल को क्रमबद्ध करने के लिए आप json.dumps (परीक्षण नहीं किया गया है, लेकिन लोरेंजो ने इसे इंगित किया है) का उपयोग नहीं कर सकते हैं। शायद भविष्य में निम्नलिखित काम करेंगे।

http://docs.python.org/2/library/json.html

import json
string = json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
object = json.loads(self.request.body)

सवाल JSON के लिए एक AppEngine Datastore मॉडल उदाहरण परिवर्तित करने के बारे में है। आप समाधान के बारे में केवल पायसन शब्दकोश को JSON में परिवर्तित करने के बारे में है
ट्यून

@tunedconsulting मैंने json.dumps के साथ डेटास्टोर मॉडल उदाहरण को अनुक्रमित करने की कोशिश नहीं की है, लेकिन यह मान लें कि यह किसी भी ऑब्जेक्ट के साथ काम करेगा। एक बग रिपोर्ट प्रस्तुत की जानी चाहिए यदि यह दस्तावेज के रूप में नहीं है जो बताती है कि json.dumps ऑब्जेक्ट को पैरामीटर के रूप में लेता है। यह केवल टिप्पणी के साथ एक टिप्पणी के रूप में जोड़ा जाता है कि यह 2009 में मौजूद नहीं था। इस जवाब को जोड़ा क्योंकि यह थोड़ा दिनांकित लगता है लेकिन अगर यह काम नहीं करेगा तो मैं इसे हटाकर खुश हूं।
HMR

1
यदि आप किसी निकाय ऑब्जेक्ट या किसी मॉडल वर्ग को टाइप करने की कोशिश करते हैं, तो आप टाइप करें : 'JSON अनुक्रमिक नहीं है' <ऑब्जेक्ट 0x0xxxxxx> पर। GAE के डेटास्टोर के अपने स्वयं के डेटाटाइप्स हैं (उदाहरण के लिए दिनांक)। वर्तमान सही उत्तर, परीक्षण किया गया और काम कर रहा है, dmw से एक है जो कुछ समस्याग्रस्त डेटाटाइप को क्रमिक रूप से परिवर्तित करता है।
देखते

@tunedconsulting इस पर आपके इनपुट के लिए धन्यवाद, मैं अपना जवाब अपडेट करूंगा।
एचएमआर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.