我应该如何在 webapp2 会话中存储实体密钥?

How should I store an entity key in a webapp2 session?

我一直在尝试使用 webapp2 在会话中存储用户数据。
我试图将父对象的键存储在会话数据中:

 self.session['client'] = client.key   

但我不断收到:

TypeError: Key('Client', 6401356696911872) is not JSON serializable  

我应该如何在会话中存储实体密钥?

我的代码相当简单:

import os  
import urllib  
import logging  

from google.appengine.api import users  
from google.appengine.ext import ndb  

import jinja2  
import webapp2  
from webapp2_extras import sessions  

class BaseHandler(webapp2.RequestHandler):  
    def dispatch(self):  
        self.session_store = sessions.get_store(request=self.request)  

        try:  
            # dispatch the request  
            webapp2.RequestHandler.dispatch(self)  
        finally:  
            # save all sessions  
            import pdb; pdb.set_trace()  
            self.session_store.save_sessions(self.response)  

    @webapp2.cached_property  
    def session(self):  
        # Returns a session using the default cookie key.  
        return self.session_store.get_session()  

JINJA_ENVIRONMENT = jinja2.Environment(  
    loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),  
    extensions=['jinja2.ext.autoescape'],  
    autoescape=True)  

DEFAULT_LEADBOOK_NAME = 'whatsmyname'  

def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):  
    """Constructs a Datastore key for a LeadBook entity with leadbook_name."""  
    return ndb.Key('LeadBook', leadbook_name)  



class Client(ndb.Model):  
    email =  ndb.StringProperty()   
    name = ndb.StringProperty(indexed=True)  
    street1 = ndb.StringProperty()  
    street2 = ndb.StringProperty()  
    city = ndb.StringProperty()  
    zipcode = ndb.IntegerProperty()  
    phone = ndb.StringProperty()  
    signup = ndb.DateTimeProperty(auto_now_add=True)  

# this just creates a Client to use  
if not ( Client.query( Client.name == "Bryan Wheelock").get()):  
    logging.info("create Admin")  
    client = Client(  
    email = "bryan@mail.com",  
    name = "Bryan Wheelock",  
    street1 = "555 Main St",  
    street2 = "unit 1",  
    city = "Atlanta",  
    zipcode = 99999,  
    phone = "(888)555-1212"  
    ).put()  


class Customer(ndb.Model):  
    client = ndb.KeyProperty(kind=Client)  
    email = ndb.StringProperty(indexed=True)  
    name = ndb.StringProperty(indexed=True)  
    street1 = ndb.StringProperty()  
    street2 = ndb.StringProperty()  
    city = ndb.StringProperty()  
    zipcode = ndb.IntegerProperty()  
    phone = ndb.StringProperty()  
    signup = ndb.DateTimeProperty(auto_now_add=True)  

class MainPage(BaseHandler):  
    def get(self):  
        leadbook_name = self.request.get('leadbook_name',  
                                            DEFAULT_LEADBOOK_NAME)  

        # This should be the Client record that shows the info of the owner of the local clinic  
        # the question is how do I get the site to show the correct Client?  
        client = Client.query( Client.name == "Bryan Wheelock").get()  
        self.session['client'] = client.key  

        template_values = {  
            'client': client,  
            'leadbook_name': urllib.quote_plus(leadbook_name),  
        }  

        template = JINJA_ENVIRONMENT.get_template('index.html')  

        self.response.write(template.render(template_values))  

class LeadBook(webapp2.RequestHandler):  
    def post(self):  
        leadbook_name = self.request.get('leadbook_name',  
                                          DEFAULT_LEADBOOK_NAME)  

        client = self.session.get('client')  
        cl = Client.query(client.key )  
        customer = Customer( client = cl.key)  
        customer.name = self.request.get('id_name')  
        customer.street = self.request.get('id_street')  
        customer.phone = self.request.get('id_phone')  
        customer.zip = self.request.get('id_zip')  
        import pdb; pdb.set_trace()  
        # How can I see the number of Customers before and after save?  
        customer.put()  

        query_params = {'leadbook_name': leadbook_name}  
        self.redirect('/?' + urllib.urlencode(query_params))  

config = {}  
config['webapp2_extras.sessions'] = {  
    'secret_key': 'my-super-secret-key',  
}  
application = webapp2.WSGIApplication([  
    ('/', MainPage),  
    ('/sign', LeadBook),  
], config = config,  
    debug=True)  


Traceback (most recent call last):  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__  
    rv = self.handle_exception(request, response, e)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__  
    rv = self.router.dispatch(request, response)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher  
    return route.handler_adapter(request, response)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__  
    return handler.dispatch()  
  File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 22, in dispatch  
    self.session_store.save_sessions(self.response)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 420, in save_sessions  
    session.save_session(response)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 205, in save_session  
    response, self.name, dict(self.session), **self.session_args)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 423, in save_secure_cookie  
    value = self.serializer.serialize(name, value)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 47, in serialize  
    value = self._encode(value)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 92, in _encode  
    return json.b64encode(value)  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 84, in b64encode  
    return base64.b64encode(encode(value, *args, **kwargs))  
  File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 55, in encode  
    return json.dumps(value, *args, **kwargs).replace("</", "<\/")  
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 250, in dumps  
    sort_keys=sort_keys, **kw).encode(obj)  
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode  
    chunks = self.iterencode(o, _one_shot=True)  
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode  
    return _iterencode(o, 0)  
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default  
    raise TypeError(repr(o) + " is not JSON serializable")  
TypeError: Key('Client', 6401356696911872) is not JSON serializable

使用 urlsafe 版本的密钥:

https://cloud.google.com/appengine/docs/python/ndb/entities#retrieving_entities

self.session['client'] = client.key.urlsafe()

检索时,使用

client = ndb.Key(urlsafe=self.session['client']).get()