Come serializzare db.Modello di oggetti json?

Quando si utilizza

from django.utils import simplejson

su oggetti di tipi che derivano dalla db.Model si genera eccezioni. Come aggirare questo?

InformationsquelleAutor Jader Dias | 2010-01-22

 

5 Replies
  1. 14

    Ok – il mio pitone non è grande, in modo che qualsiasi aiuto sarebbe apprezzato – non Avete bisogno di scrivere un parser – questa è la soluzione:

    aggiungere questa utlity classe http://code.google.com/p/google-app-engine-samples/source/browse/trunk/geochat/json.py?r=55

     import datetime  
     import time 
    
     from google.appengine.api import users 
     from google.appengine.ext import db 
    
    #this is a mod on the orinal file for some reason it includes its own simplejson files i have ref django!
     from django.utils import simplejson  
    
     class GqlEncoder(simplejson.JSONEncoder): 
    
       """Extends JSONEncoder to add support for GQL results and properties. 
    
       Adds support to simplejson JSONEncoders for GQL results and properties by 
       overriding JSONEncoder's default method. 
       """ 
    
       # TODO Improve coverage for all of App Engine's Property types. 
    
       def default(self, obj): 
    
         """Tests the input object, obj, to encode as JSON.""" 
    
         if hasattr(obj, '__json__'): 
           return getattr(obj, '__json__')() 
    
         if isinstance(obj, db.GqlQuery): 
           return list(obj) 
    
         elif isinstance(obj, db.Model): 
           properties = obj.properties().items() 
           output = {} 
           for field, value in properties: 
             output[field] = getattr(obj, field) 
           return output 
    
         elif isinstance(obj, datetime.datetime): 
           output = {} 
           fields = ['day', 'hour', 'microsecond', 'minute', 'month', 'second', 
               'year'] 
           methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 
               'timetuple'] 
           for field in fields: 
             output[field] = getattr(obj, field) 
           for method in methods: 
             output[method] = getattr(obj, method)() 
           output['epoch'] = time.mktime(obj.timetuple()) 
           return output 
    
         elif isinstance(obj, time.struct_time): 
           return list(obj) 
    
         elif isinstance(obj, users.User): 
           output = {} 
           methods = ['nickname', 'email', 'auth_domain'] 
           for method in methods: 
             output[method] = getattr(obj, method)() 
           return output 
    
         return simplejson.JSONEncoder.default(self, obj) 
    
    
     def encode(input): 
       """Encode an input GQL object as JSON 
    
         Args: 
           input: A GQL object or DB property. 
    
         Returns: 
           A JSON string based on the input object.  
    
         Raises: 
           TypeError: Typically occurs when an input object contains an unsupported 
             type. 
         """ 
       return GqlEncoder().encode(input)   

    salva con nome json.py

    UTILIZZARE

    import cgi
    import os
    import json 
    
    from google.appengine.ext.webapp import template
    from google.appengine.api import users
    from google.appengine.ext import webapp
    from google.appengine.ext.webapp.util import run_wsgi_app
    from google.appengine.ext import db
    
    
    class Greeting(db.Model):
        author = db.UserProperty()
        content = db.StringProperty(multiline=True)
        date = db.DateTimeProperty(auto_now_add=True)
    
    class MainPage(webapp.RequestHandler):
        def get(self):
            greetings_query = Greeting.all().order('-date')
            greetings = greetings_query.fetch(5)
    
            if users.get_current_user():
                url = users.create_logout_url(self.request.uri)
                url_linktext = 'Logout'
            else:
                url = users.create_login_url(self.request.uri)
                url_linktext = 'Login'
    
            template_values = {
                'greetings': greetings,
                'url': url,
                'url_linktext': url_linktext,
                }
    
            path = os.path.join(os.path.dirname(__file__), 'index.html')
            self.response.out.write(template.render(path, template_values))
    
    
    class Guestbook(webapp.RequestHandler):
        def post(self):
            greeting = Greeting()
    
            if users.get_current_user():
                greeting.author = users.get_current_user()
    
            greeting.content = self.request.get('content')
            greeting.put()
            self.redirect('/')
    
    
    
    #here i return my json feed - simple implementaion for example
    class FeedHandler(webapp.RequestHandler):
    
      def get(self):
        """Retrieve a feed"""
        user = None
    
        greetings_query = Greeting.all().order('-date')
        rs= greetings_query.fetch(5)
    #this is the part that calls the encoder - dosnt cause an exception
        data = json.encode(rs)
    
    
    
    #roll out to browser -might need to check my headers etc
        self.response.headers['Content-Type'] = 'application/json; charset=utf-8'  
        self.response.out.write(data)
    
    
    
    
    application = webapp.WSGIApplication(
                                           [
                                           ('/', MainPage),
                                           ('/sign',Guestbook),
                                           ('/feed',FeedHandler),
                                           ], debug=True
                                        )
    
    def main():
        run_wsgi_app(application)
    
    if __name__ == "__main__":
        main()

    Questo è il browser risposta:

    [{“content”: “”, “data”: {“ctime”: “Sab Gen 23 02:40:22 2010”, “ora”: 2, “isoweekday”: 6, “mese”: 1, “secondo”: 22, “microsecondo”: 434000, “isocalendar”: [2010, 3, 6], “timetuple”: [2010, 1, 23, 2, 40, 22, 5, 23, -1], “per” anno: 2010, “epoca”: 1264214422.0, “isoformat”: “2010-01-23T02:40:22.434000”, “day”: 23, “minuto”: 40}, “autore”: {“nickname”: “[email protected]”, “email”: “[email protected]”, “auth_domain”: “gmail.com”}}, {“content”: “”, “data”: {“ctime”: “Sab Gen 23 01:12:43 2010”, “ora”: 1, “isoweekday”: 6, “mese”: 1, “secondo”: 43, “microsecondo”: 972000, “isocalendar”: [2010, 3, 6], “timetuple”: [2010, 1, 23, 1, 12, 43, 5, 23, -1], “per” anno: 2010, “epoca”: 1264209163.0, “isoformat”: “2010-01-23T01:12:43.972000”, “day”: 23, “minuto”: 12}, “autore”: {“nickname”: “[email protected]”, “email”: “[email protected]”, “auth_domain”: “gmail.com”}}, {“content”: “prova”, “date”: {“ctime”: “Ven Gen 22 22:32:13 2010”, “ora”: 22, “isoweekday”: 5, “mese”: 1, “secondo”: 13, “microsecondo”: 659000, “isocalendar”: [2010, 3, 5], “timetuple”: [2010, 1, 22, 22, 32, 13, 4, 22, -1], “per” anno: 2010, “epoca”: 1264199533.0, “isoformat”: “2010-01-22T22:32:13.659000”, “day”: 22, “minuto”: 32}, “autore”: {“nickname”: “[email protected]”, “email”: “[email protected]”, “auth_domain”: “gmail.com”}}, {“content”: “”, “data”: {“ctime”: “Ven Gen 22 22:29:49 2010”, “ora”: 22, “isoweekday”: 5, “mese”: 1, “secondo”: 49, “microsecondo”: 358000, “isocalendar”: [2010, 3, 5], “timetuple”: [2010, 1, 22, 22, 29, 49, 4, 22, -1], “per” anno: 2010, “epoca”: 1264199389.0, “isoformat”: “2010-01-22T22:29:49.358000”, “day”: 22, “minuto”: 29}, “autore”: {“nickname”: “[email protected]”, “email”: “[email protected]”, “auth_domain”: “gmail.com”}}, {“content”: “ah, funziona!\r\n”, “data”: {“ctime”: “Ven Gen 22 22:29:22 2010”, “ora”: 22, “isoweekday”: 5, “mese”: 1, “secondo”: 22, “microsecondo”: 995000, “isocalendar”: [2010, 3, 5], “timetuple”: [2010, 1, 22, 22, 29, 22, 4, 22, -1], “per” anno: 2010, “epoca”: 1264199362.0, “isoformat”: “2010-01-22T22:29:22.995000”, “day”: 22, “minuto”: 29}, “autore”: {“nickname”: “[email protected]”, “email”: “[email protected]”, “auth_domain”: “gmail.com”}}]

    • Sono stato di attuazione mia ed è così vicino il file collegato
    • Non è stato immediatamente chiaro per me (python e GAE newbie), ma è necessario includere il simplejson modulo di codice nella vostra GAE file/pacchetti.
    • Come utilizzare questo per i db modello di Riferimento immobile? (Ho un db di classe, che l’hv altro db modello di riferimento e di questo soln non funziona)
    • ottengo questo: tupla: (‘datetime.data(2011, 2, 24) non è JSON serializable’,)
    • Nota che GAE su Python 2.7, ora include il json modulo come un sostituto per django.utils.simplejson quindi, se si utilizza 2.7, il riferimento deve essere cambiato, e il file dovrà probabilmente essere rinominato. Ho anche aggiunto una riga nel db.Modello caso che dice output['key'] = str(obj.Key()) Che modo posso vedere la chiave per la pubblicazione di aggiornamenti in seguito e quant’altro.
  2. 10

    L’esempio fornito da Jader Dias funziona bene per la mia preoccupazione dopo alcuni twaeking. Rimuovere la codifica metodo in quanto contiene un riferimento circolare. Il regolato classe dovrebbe assomigliare a questo:

    import datetime  
    import time 
    
    from google.appengine.api import users 
    from google.appengine.ext import db 
    from django.utils import simplejson  
    
    
    class GqlEncoder(simplejson.JSONEncoder): 
    
        """Extends JSONEncoder to add support for GQL results and properties. 
    
        Adds support to simplejson JSONEncoders for GQL results and properties by 
        overriding JSONEncoder's default method. 
        """ 
    
        # TODO Improve coverage for all of App Engine's Property types. 
    
        def default(self, obj): 
    
            """Tests the input object, obj, to encode as JSON.""" 
    
            if hasattr(obj, '__json__'): 
                return getattr(obj, '__json__')() 
    
            if isinstance(obj, db.GqlQuery): 
                return list(obj) 
    
            elif isinstance(obj, db.Model): 
                properties = obj.properties().items() 
                output = {} 
                for field, value in properties: 
                    output[field] = getattr(obj, field) 
                return output 
    
            elif isinstance(obj, datetime.datetime): 
                output = {} 
                fields = ['day', 'hour', 'microsecond', 'minute', 'month', 'second', 'year'] 
                methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 'timetuple'] 
                for field in fields: 
                    output[field] = getattr(obj, field) 
                for method in methods: 
                    output[method] = getattr(obj, method)() 
                output['epoch'] = time.mktime(obj.timetuple()) 
                return output
    
            elif isinstance(obj, datetime.date): 
                output = {} 
                fields = ['year', 'month', 'day'] 
                methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 'timetuple'] 
                for field in fields: 
                    output[field] = getattr(obj, field) 
                for method in methods: 
                    output[method] = getattr(obj, method)() 
                output['epoch'] = time.mktime(obj.timetuple()) 
                return output 
    
            elif isinstance(obj, time.struct_time): 
                return list(obj) 
    
            elif isinstance(obj, users.User): 
                output = {} 
                methods = ['nickname', 'email', 'auth_domain'] 
                for method in methods: 
                    output[method] = getattr(obj, method)() 
                return output 
    
            return simplejson.JSONEncoder.default(self, obj) 

    Come ho salvato questa classe in un file chiamato utils.py e quando appropriato importazione utilizzando

    import utils

    Poi ho chiamata utils.GqlEncoder().codificare(risultati), ad esempio:

    query = User.all()
    results = query.fetch(10)
    
    self.response.headers['Content-Type'] = "text/plain" # Alt. application/json
    self.response.out.write( utils.GqlEncoder().encode(results) )

    Il risultato dovrebbe essere qualcosa di simile a questo (ho aggiunto qualche riga di feed in modo da rendere un po ‘ più facile da leggere):

    [
    {"date": {"ctime": "Tue Feb 23 10:41:21 2010", "hour": 10, "isoweekday": 2, "month": 2, 
            "second": 21, "microsecond": 495535, "isocalendar": [2010, 8, 2], "timetuple": [2010, 2, 23, 10, 41, 21, 1, 54, -1], 
            "year": 2010, "epoch": 1266921681.0, "isoformat": "2010-02-23T10:41:21.495535", "day": 23, "minute": 41}, 
    "claimed_id": "https:\/\/www.google.com\/accounts\/o8\/id?id=abcdefghijklmnopqrstuvxyz", 
    "display_name": "Alfred E Neumann", 
    "email": null, 
    "full_name": "Alfred E Neumann"
    }, 
    {"date": {"ctime": "Tue Feb 23 11:00:54 2010", "hour": 11, "isoweekday": 2, "month": 2, 
            "second": 54, "microsecond": 805261, "isocalendar": [2010, 8, 2], "timetuple": [2010, 2, 23, 11, 0, 54, 1, 54, -1], 
            "year": 2010, "epoch": 1266922854.0, "isoformat": "2010-02-23T11:00:54.805261", "day": 23, "minute": 0}, 
    "claimed_id": "http:\/\/openid.domain.net\/john", 
    "display_name": "", 
    "email": "[email protected]", 
    "full_name": "John Parnefjord"
    }
    ]
  3. 3

    json non può essere utilizzato per serializzare qualcosa di più di tipi di base come dicts, elenchi, int/long, e stringhe (questo non è esaustivo). Per esempio, anche questi semplici comandi non funzionano:

    import json
    json.dumps(object())

    Se si desidera serializzare django oggetti, si deve far riferimento a django documentazione sulla serializzazione, che consentirà di utilizzare le proprie librerie, ma non supportano il formato json.

    • A proposito, il libreria json che è incluso in Python 2.6 è funzionalmente equivalente a simplejson.
    • Sono abbastanza sicuro di Jader significa che il appengine db.Gli oggetti del modello, non il django di quelli.
    • non funziona con Google App Engine db.Model, perché simplejson.dumps restituisce object is not JSON serializable e serializers.serialize restituisce object has no attribute '_meta'
  4. 0

    In quanto non riuscivo a trovare una soluzione adeguata che ho scritto la mia, che non è esattamente un serializzatore JSON, ma un Javascript serializzatore

    from google.appengine.ext import db
    from google.appengine.api.datastore_types import *
    
    def dumpStr(obj):
        return "'" + obj + "'"
    
    def dumps(obj):
        if isinstance(obj, str):
            return dumpStr(obj)
        elif obj == None:
            return None
        elif isinstance(obj, list):
            items = [];
            for item in obj:
                items.append(dumps(item))
            return '[' + ','.join(items) + ']'
        elif isinstance(obj, datetime.datetime):
            return "new Date('%s')" % obj.ctime()
        properties = [];
        for property in dir(obj):
            if property[0] != '_':
                value = obj.__getattribute__(property)
                valueClass = str(value.__class__)
                if not(('function' in valueClass) or ('built' in valueClass) or ('method' in valueClass)):
                    value = dumps(value)
                    if value != None:
                        properties.append("'" + property + "':" + value)
        if len(properties) == 0:
            return str(obj)
        else:
            return '{' + ','.join(properties) + '}'
    • Solo un avvertimento: questo non produrre JSON valido per tutti gli ingressi. Per esempio, se una stringa contiene un ' o un \n JSON non sarà valido, o se obj contiene un numero. Quindi, non utilizzare questo — alta votato risposta.
  5. -1

    Da quello che posso capire e sono nuovo di python – con google app engine è possibile aggirare il problema per serializzare l’oggetto del modello per un dictioanry oggetto python e quindi utilizzare semplici json per eseguire il dump come una stringa json – questo non ha senso per me – forse qualcuno ha il sapere per serialise per un ditionary (pickel?)
    Qualsiasi aiuto su questo sarebbe di AIUTO! non colpito dal fatto che google app engine non ha integrato la soluzione per questo.

    • provato il codice e ottenuto questo errore “ritorno GqlEncoder().codificare(input) RuntimeError: massima profondità di ricorsione superato”

Lascia un commento