Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App Engine return JSON from JsonProperty

I like how the JsonProperty automatically encodes a Python structure into JSON when the property is put into the data store, and automatically decodes it when retrieved. However, it would be nice to send that JSON data to a web browser without having to encode it again. Is there a way to get the raw JSON data (that is, prevent the decoding)?

class DataForBrowser(ndb.Models)
    json = ndb.JsonProperty()

    def get_json(self):
        return ???
like image 342
Brent Washburne Avatar asked Sep 02 '13 15:09

Brent Washburne


1 Answers

So what you want is to have a dict that gets encoded when saved to the datastore but not decoded upon retrieving it... What happens "under the hood" is that a JsonProperty is a subclass of BlobProperty that gets encoded (json.dumps()) every time it gets written to the datastore and decoded (json.loads()) every time it's read. This can be done only with a property subclass that eliminates one of these functions (but I don't think it's wise to have different behaviors for the property according to the state the entity is). Just for "educational purposes" let's see what will happen then

from google.appengine.ext import ndb
import json

class ExtendedJsonProperty(ndb.BlobProperty):
  def _to_base_type(self, value):
    return json.dumps(value) 

  def _from_base_type(self, value):
    return value
    # originally return json.loads(value)

class DataForBrowser(ndb.Model):
    json = ExtendedJsonProperty()


data = {'a': 'A'}
data_for_browser = DataForBrowser()
data_for_browser.json = data
print type(data_for_browser.json)  # returns <type 'dict'>
data_for_browser.put()
print type(data_for_browser.json) # returns <type 'str'>
data_for_browser_retrieverd = DataForBrowser.query().get()
print type(data_for_browser_retrieverd.json) # returns <type 'str'>

If you need to make use of the dict in your code then I suggest using a JsonProperty and adding a new property method that will return the dict as JSON and use that.

@property
def json_as_json(self):
  return json.dumps(self.json)

If you use the dict only to create the JSON data then just use a BlobProperty and pass through json.dumps() before assigning the data to the property

like image 197
nizz Avatar answered Oct 16 '22 15:10

nizz