google-app-engine NDB with Python on AppEngine


NDB relates models as python objects, which can be stored and accessed in the Appengine NoSQL datastore, available to all AppEngine applications.

from google.appengine.ext import ndb


class Series(ndb.Model):
    """TV Series Object"""
    folder_name = ndb.StringProperty()
    title = ndb.StringProperty()
    rating = ndb.StringProperty()
    banner_blob_key = ndb.BlobKeyProperty()
    year = ndb.IntegerProperty()
    plot = ndb.TextProperty()
    genre = ndb.StringProperty(repeated=True)
    json_of_show = ndb.JsonProperty()
    date_added = ndb.DateTimeProperty(auto_now_add=True)
    date_updated = ndb.DateTimeProperty(auto_now=True)

class Episode(ndb.Model):
    """Episode Object (Series have Episodes)"""
    series = ndb.KeyProperty(kind=Series)
    episode_title = ndb.StringProperty()
    season = ndb.IntegerProperty()
    episode_number = ndb.IntegerProperty()
    thumb_blob_key = ndb.BlobKeyProperty()
    episode_json = ndb.JsonProperty()
    date_added = ndb.DateTimeProperty(auto_now_add=True)
    date_updated = ndb.DateTimeProperty(auto_now=True)

With out models defined we can create new objects for entry to the datastore:

nfo = xmltodict.parse(my_great_file.xml)
s = Series()
s.folder_name = gcs_file.filename[:-10]
s.title = nfo['tvshow'].get('title', None)
s.rating = nfo['tvshow'].get('rating', None)
#  Below we use the google cloud storage library to generate a blobkey for a GCS file
s.banner_blob_key = BlobKey((blobstore.create_gs_key('/gs' + gcs_file.filename[:-10] + 'banner.jpg')))
s.year = int(nfo['tvshow'].get('year', None))
s.plot = nfo['tvshow'].get('plot', None)
#  genre is a repeated type, and can be stored as a list
s.genre = nfo['tvshow'].get('genre', 'None').split('/')
s.json = json.dumps(nfo)
s.put_async()  #put_async writes to the DB without waiting for confirmation of write.

Adding an episode and relating it to a Series:

nfo = xmltodict.parse(my_great_file.xml)

epi = Episode()
epi.show_title = nfo['episodedetails'].get('showtitle', None)
epi.title = nfo['episodedetails'].get('title', None)

#  We'll query the Series for use later
show_future = Series.query(Series.title == epi.show_title).get_async()

epi.json = json.dumps(nfo)                    
... #  We perform other assorted operations to store data in episode properties                        

#  Ask for the show we async queried earlier                    
show = show_future.get_result()
#  Associate this episode object with a Series by Key
epi.series = show.key
epi.put_async()  #  Write the object without waiting 

Later, to retrieve all Series:

shows = Series.query() 

Filters could be applied if all shows were not desired.

More reading: