为什么Flask会话的值必须是JSON可序列化的?

时间:2017-03-21 20:33:03

标签: flask

我试图在Flask应用程序中为用户会话实例化一个基本的Model实例。我要求我的类是JSON可序列化的,这让我措手不及。我认为会话字典只是一个存储会话信息的任意构造,但听起来有更多关于其使用的约束,其中一个显然是值是JSON可序列化的。还有哪些其他约束,这个JSON约束的目的是什么? Web应用程序是否期望通过JSON持久保存用户会话?这个要求来自哪里?受到启发?

@app.route( '/' , methods=['GET', 'POST'] )
def index():
    """index  takes user to the home page of the application.
    """

    # Create model instance for this user session
    if 'model' not in session :
        session['model'] = Model( )


File "C:\Anaconda3\lib\site-packages\flask\json.py", line 83, in default
return _json.JSONEncoder.default(self, o)
File "C:\Anaconda3\lib\json\encoder.py", line 173, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Model.Model object at 0x000000000770B6D8> is not JSON serializable

只是为了获得额外的背景,看起来会话对象是一个LocalProxy实例,它可能会提到事物的设计。

>>> type( session )
<class 'werkzeug.local.LocalProxy'>

1 个答案:

答案 0 :(得分:1)

好的,所以在Miguel Grinberg的Flask Workshop在Pycon 2015上有一些很好的评论。对JSON支持的需求与这个会话数据的持久性有关,就像客户端上的cookie一样。因此,数据必须序列化以弥合服务器和客户端之间的差距。据他说......

  

所以flask支持这个会话对象,...在任何路由函数内   当您处理请求时,您将会话称为字典。   你写的任何东西都会被记住,下次你可以找到它   它将在那里,它将是用户特定的。

     

如果你有兴趣知道它是如何工作的,这就是Flask的内部,   你写给这本词典的任何东西,Flask都会放入一个cookie   它会将其发送给客户。所以这将存储在客户端   网页浏览器。这将是一个密码签名的cookie   确保用户不会篡改它,没有   攻击可能。你可以看到cookie里有什么,但你不能   修改它。默认情况下,Flask将数据本身写入cookie和   那个cookie送到客户端。还有很多其他框架可以做什么   默认是不同的。基本上他们做的是他们写入数据   服务器中的文件或数据库,然后他们写一个cookie   标识该数据的id,然后它们在中发送id   曲奇饼。所以Flask默认会在cookie中发送整个数据   没有必要在服务器中存储任何东西。

所以在我的特殊情况下,为了解决这个问题,我必须实现一个JSONEncoder,然后在将它转移到我的会话之前对其进行编码

<<Model.py>>
class ModelEncoder( JSONEncoder ) :
    def default( self , obj ) :
        if isinstance( obj , Model ):
            return obj.to_json()
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default( self , obj )

class Model( JSONEncoder ) :
    ....
    def to_json( self ) :
        """
        to_json transforms the Model instance into a JSON string
        """
        return jsonpickle.encode( self )


<<FlaskApp.py>>
    ...
    # Create model instance for this user session
    if 'model' not in session :
        session['model'] = ModelEncoder().encode( Model( ) )