如何在Flask中将会话传递到模板以及应用程序的功能之间? [英] How session is passed to templates and between functions of the app, in Flask?
问题描述
在调查我遇到的另一个难题期间一般而言,在Flask会话中,我试图更好地理解Flask会话的工作原理.
根据有关会话的Flask文档 session
对象本身是代理.
我的理解(也就是说,很可能在某种程度上是错误的,这就是这个问题所要涉及的=)意思是:
-
代理
session
对象可从应用程序访问,并用于根据需要修改读取的数据 -
通常,proxy-
会话
会将其更改立即转移到代理-session
(会话),因此没有能力/不需要从会话访问session._get_current_object()
.模板 -
因为字典(
session
是字典)是可变的,所以我认为它的id在会话期间应该保持不变(尽管内容可以修改) -
实际的
session
(代理对象,可以通过session._get_current_object()
获得)永远不要更改其ID
现在,当我尝试检查自己的假设时-我遇到的行为使我有些困惑.
考虑以下代码:
my_app.py
从flask导入 烧瓶,render_template,会议,)app = Flask(__ name__)app.secret_key ='一些随机密钥'@ app.route('/create/')def create():session ['example'] = ['one','two']print_ids()返回str(session ['example'])@ app.route('/modify/')def Modify():session ['example'].append('three')print_ids()返回render_template('my_template.html',id = id)@ app.route('/display/')def display():print_ids()返回str(session ['example'])def print_ids():进口检验calling_function = inspect.stack()[1] [3]打印('')print(calling_function +:会话ID为:{}".format(id(session)))print(calling_function +``:session ['example'] ID为{}''.format(id(session('example'])))打印('________________________________')print(calling_function +:session._get_current_object()ID为:{}".format(id(session._get_current_object()))print(calling_function +:session._get_current_object()['example'] ID为:{}".format(id(session(_session__get_current_object()['example']))))
my_template.html
<!doctype html>< html>< head>< title>显示会话['example']</title></head><身体>< div>{%,如果会话['示例']%}{{session ['example']}}< br/>会话ID为:{{id(session)}}< br/>session ['example'] ID为:{{id(session ['example'])}}< br/>{% 别的 %}没有设置session ['example'] =({% 万一 %}</div></body></html>
这个想法是打印proxy- session
, session ['example']
(这是一个列表),代理- session
的ID>(即 session._get_current_object()
)和代理- session ['example']
(即 session._get_current_object()['example']
>)来自每个函数,以及呈现的模板上的 id(session)
和 id(session ['example'])
,以跟踪使用了什么在哪里.
以下是结果:
<代码> .../create/#id(会话)4338311808#id(session._get_current_object())4343709776#id(session ['example'])4343654376#id(session._get_current_object()['example'])4343654376.../调整/#id(会话)4338311808#id(session._get_current_object())4344315984#id(session ['example'])4343652720#id(session._get_current_object()['example'])4343652720呈现了my_template.html#id(会话)4344315984#id(session ['example'])4343652720.../展示/#id(会话)4338311808#id(session._get_current_object())4344471632#id(session ['example'])4341829576#id(session._get_current_object()['example'])4341829576# 再一次.../展示/#id(会话)4338311808#id(session._get_current_object())4344471632#id(session ['example'])4344378072#id(session._get_current_object()['example'])4344378072
我正在努力理解的是:
-
总体上,我对Flask会议概念的误解/错误假设是什么?
-
为什么每次显示时更改
session ['example']
和session._get_current_object()['example']
的ID(以及其他所有方法,但是特别显示,因为它不会进行任何修改,所以我希望所有id都保持不变) -
为什么
session._get_current_object()
的ID更改而session
的ID不变? -
由于
session ['example']
和session._get_current_object()['example']
的ID在任何函数的上下文中都是相同的,所以我会假设如果一个对象被更改-那么两个对象都被更改,因为它们是同一个对象.话虽如此,并考虑到
session._get_current_object()['example']
位于代理(即真实")session
内部期望以下内容:
<代码> .../create/#返回['one','two'].../modify/#将渲染包含['one','two','three']的页面.../display/#return ['one','two','3']作为代理和代理会话,应该已经被修改
但是作为我之前发现了-这没有发生.那么为什么ID相同?
您的大部分困惑来自对Flask代理对象的误解,例如 session
, g
和请求
.
这些对象所做的所有事情就是确保您获得了当前线程的正确数据;它们在全局对象(可被所有线程访问,易于导入并在Flask代码中使用)和存储在 session.foo 间接访问并返回与 session._get_current_object().foo
完全相同的对象(这就是它们的ID始终匹配的原因).
因此,当访问 session
对象时,代理是透明的.除非您想与另一个线程共享代理对象,否则您不必担心这一切.
为每个请求创建一个新的 您访问的代理对象.这是因为会话的内容取决于每个请求中的数据.Flask的会话机制是可插入的,但是默认实现将所有数据存储在经过加密签名的cookie中,如果您希望能够与之交互,则需要将其解码为Python数据.每个/create/
,/modify/
和/display/
URL均作为单独的请求处理,因此它们均从您的服务器加载会话数据请求进入新的Python对象;他们的ID通常会有所不同.
请求完成后,会话对象再次消失.您别无选择,因为在同一个线程中出现的新请求需要将来自该新请求的会话数据呈现给Flask代码,而不是来自旧请求的数据.
所有这些意味着 id()
的输出在此处毫无意义. id()
是一个数字,对于当前Python进程中的所有当前 active 对象都是唯一的.这意味着从内存中删除的对象的id可以重复使用,只是因为您在两个时间点看到相同的 id()
值并不意味着您具有相同的对象.而且,即使您具有相同的 data (值相等)也不意味着您在内存中具有相同的对象,即使它们的id相同.可以删除旧对象,而只需重新创建一个具有相同值的新对象即可.
在后台,Flask调用 During investigation of another conundrum that I had with Flask sessions, I have tried to better my understanding of how Flask sessions work, in general. According to Flask documentation on sessions My understanding (that is, in all probability, wrong in some way, and this is what this question is about =) of what it means is: the proxy normally, proxy- in case if proxied- templates receive the 'original' session (i.e. proxied- as dictionaries (which the actual Now, when I have tried to check my assumptions - the behaviour I've encountered confused me a bit. Consider the following code: my_app.py my_template.html The idea is to print id's of proxy- Here are the results: Things I'm striving to understand are: What are my misunderstandings/wrong assumptions, concerning Flask sessions concept, in general? Why ids of Why id of Since ids of With that being said, and taking into account that
But as I have previously discovered - it's not happening. So why ids are the same? Most of your confusion comes from misunderstandings about Flask proxy objects, such as All that these objects do is make sure you get the correct data for the current thread; they proxy between a global object (accessible by all threads, easy to import and use in your Flask code), to an object stored in thread-local storage, which is an object that transparently differentiates attribute access by thread id. There is no need for locking or 'waiting' in this, proxied objects are never used by more than one thread. So when accessing the The proxied object you access is created a-new for every request. That's because the contents of a session are dependent on data in each request. Flask's session machinery is pluggable, but the default implementation stores all data in a cryptographically signed cookie, which needs to be decoded into Python data if you want to be able to interact with it. Each of your After a request is done, the session object is gone again. You can't have this any other way, because a new request coming in on the same thread needs to present the session data from that new request to your Flask code, not the data from the old request. All this means that the output of Under the hood, Flask calls the Saving only happens when the session object has been 'changed', ( 这篇关于如何在Flask中将会话传递到模板以及应用程序的功能之间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!分配给
设置为 save_session()调用code>方法
再次保存会话,并且丢弃该会话对象.默认实现是 SecureSessionInterface
对象在请求中查找特定的cookie,如果存在且具有有效的签名,则将数据解码为带标签的JSON(紧凑型JSON序列化),并返回 session.modified True
)时发生保存.请注意,默认实现仅在直接操作会话映射(在映射本身中设置,更新或删除键)时才将 modified
设置为 True
,而不是在更改存储在其中的可变对象时会议; session ['foo'] ='bar'
是可检测的,但是如果您在会话中存储了列表或字典,则使用诸如 session ['spam'] [0]='ham'
将不会被检测到.要么重新设置可变对象( session [key] = session [key]
),要么将 modified
标志手动设置为 True
.>
session
object itself is a proxy.
session
object is accessed from the app and is used to modify read data as neededsession
will transfer it's changes to proxied-session
right away (except for the change of mutables in proxy-session
)session
is busy (in case of a multi-thread app), proxy-session
will wait until proxied-session
available, and then transfer it's changes to proxied-session
session
), so there is no ability/need to access session._get_current_object()
from the templatessession
is) are mutable, I'd assume it's id should remain unchanged for the length of session (though content could be modified)session
(proxied object, that is available via session._get_current_object()
) should never change its ID
from flask import (
Flask,
render_template,
session,
)
app = Flask(__name__)
app.secret_key = 'some random secret key'
@app.route('/create/')
def create():
session['example'] = ['one', 'two']
print_ids()
return str(session['example'])
@app.route('/modify/')
def modify():
session['example'].append('three')
print_ids()
return render_template('my_template.html', id=id)
@app.route('/display/')
def display():
print_ids()
return str(session['example'])
def print_ids():
import inspect
calling_function = inspect.stack()[1][3]
print('')
print(calling_function + ": session ID is: {}".format(id(session)))
print(calling_function + ": session['example'] ID is {}".format(id(session['example'])))
print('________________________________')
print(calling_function + ": session._get_current_object() ID is: {}".format(id(session._get_current_object())))
print(calling_function + ": session._get_current_object()['example'] ID is: {}".format(id(session._get_current_object()['example'])))
<!doctype html>
<html>
<head><title>Display session['example']</title></head>
<body>
<div>
{% if session['example'] %}
{{ session['example'] }}
<br />
session ID is: {{ id(session) }}
<br />
session['example'] ID is: {{ id(session['example']) }}
<br />
{% else %}
session['example'] is not set =(
{% endif %}
</div>
</body>
</html>
session
, session['example']
(which is a list), proxied-session
(i.e. session._get_current_object()
) and proxied-session['example']
(i.e. session._get_current_object()['example']
) from every function, as well as id(session)
and id(session['example'])
on the rendered template, in order to track down what is used where..../create/
# id(session) 4338311808
# id(session._get_current_object()) 4343709776
# id(session['example']) 4343654376
# id(session._get_current_object()['example']) 4343654376
.../modify/
# id(session) 4338311808
# id(session._get_current_object()) 4344315984
# id(session['example']) 4343652720
# id(session._get_current_object()['example']) 4343652720
rendered my_template.html
# id(session) 4344315984
# id(session['example']) 4343652720
.../display/
# id(session) 4338311808
# id(session._get_current_object()) 4344471632
# id(session['example']) 4341829576
# id(session._get_current_object()['example']) 4341829576
# one more time
.../display/
# id(session) 4338311808
# id(session._get_current_object()) 4344471632
# id(session['example']) 4344378072
# id(session._get_current_object()['example']) 4344378072
session['example']
and session._get_current_object()['example']
are changed on every hit of display (and every other method, but display in particular, since it does not modify anything, I would expect all ids to remain unchanged)?session._get_current_object()
changes and id of session
is not?session['example']
and session._get_current_object()['example']
are identical in context of any function, I would assume that if one object is changed - then both are changed, as they are the same object.session._get_current_object()['example']
is inside proxied (i.e. 'real') session
I'd expect the following: .../create/ # return ['one', 'two']
.../modify/ # will render page containing ['one', 'two', 'three']
.../display/ # return ['one', 'two', 'three'] as proxy and proxied sessions should have been modified
session
, g
and request
.session.foo
indirectly accesses and returns the exact same object as session._get_current_object().foo
does (which is why their ids always match).session
object, proxying is transparent. This is not something you ever need worry about unless you want to share a proxied object with another thread./create/
, /modify/
and /display/
URLs are handled as separate requests, so they all load session data from your request into new Python objects; their ids will usually differ.id()
is meaningless here. id()
is a number that is unique for all currently active objects in the current Python process. This means that the ids of objects that are removed from memory can be reused, just because you have seen the same id()
value at two points in time doesn't mean you have the same object. And just because you have the same data (value equality) doesn't mean that you have the same object in memory, even if their id is the same. The old object could have been deleted and a new object could simply have been re-created with the same value.open_session()
method on the object assigned to Flask().session_interface
at the start of each request. At the end, the save_session()
method is called to save the session again, and the session object is discarded. The default implementation is the SecureSessionInterface
object, which looks for a specific cookie on the request, and if present and with a valid signature, decodes the data as tagged JSON (a compact JSON serialisation), and returns a SecureCookieSession
instance with that data. This is the object that session
proxies for, and is returned by session._get_current_object()
. When saving, the data is serialised to tagged JSON again, signed, and added to the response as an outgoing Set-Cookie
header.session.modified
is set to True
). Note that the default implementation only sets modified
to True
when directly manipulating the session mapping (setting, updating or deleting keys in the mapping itself), not when changing mutable objects stored in the session; session['foo'] = 'bar'
is detectable, but if you stored a list or dictionary in the session, then mutating those with expressions like session['spam'][0] = 'ham'
will not be detected. Either re-set the mutable object (session[key] = session[key]
) or set the modified
flag to True
manually.