session和蓝图
title: session和蓝图
date: 2018-10-29 17:18:00
tags:flask
categories: 十月,2018
session
- 这是一个基本的代码
from flask import Flask
#1. 实例化Flask对象
app = Flask(__name__)
# 2. 设置路由
"""
app.url_map = [
('/index',index),
('/login',login),
]
"""
@app.route('/index')
def index():
return "index"
if __name__ == '__main__':
# 3. 启动socket服务端
app.run()
# 4. 用户请求到来
app.__call__
app.wsgi_app
app.request_class
app.session_interface
- 用户请求到来,先执行__call__方法,然后执行wsgi_app函数
- def wsgi_app(self, environ, start_response):
- """
- 1.获取environ并对其进行再次封装
- 2.从environ中获取名称为session的cookie,解密,反序列化
- 3.两个东西放到Local中
- """
# ctx = RequestContext(self, environ) #self是app对象,environ请求相关的原始数据
# ctx.request = Request(environ)
# ctx.session = None
ctx = self.request_context(environ)
error = None
try:
try:
# 将ctx放到"Local"上
# 执行 SecureCookieSessionInterface.open_session,去rookie中获取值并给ctx.session重新赋值
ctx.push()
# 4.执行视图函数
# 5."Local"获取session,加密,序列化 ==》写cookie
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 6."Local"位置清空
ctx.auto_pop(error)
执行视图函数
def full_dispatch_request(self):
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request() # 调用视图函数
except Exception as e:
rv = self.handle_user_exception(e)
#视图函数执行完毕后,进行善后工作
return self.finalize_request(rv)
open_session
def open_session(self, app, request):
s = self.get_signing_serializer(app)
if s is None:
return None
val = request.cookies.get(app.session_cookie_name)
if not val:
return self.session_class()
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
save_session
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
# If the session is modified to be empty, remove the cookie.
# If the session is empty, return without setting the cookie.
if not session:
if session.modified:
response.delete_cookie(
app.session_cookie_name,
domain=domain,
path=path
)
return
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add('Cookie')
if not self.should_set_cookie(app, session):
return
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session))
response.set_cookie(
app.session_cookie_name,
val,
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite
)
蓝图
- 目标:给开发者提供目录结构
- 其他:
- 自定义模板、静态文件
- 功能式架构
- 在功能式架构中,按照每部分代码的功能来组织你的应用。
- 所有模板放到同一个文件夹中,静态文件放在另一个文件夹中,
- 而视图放在第三个文件夹中。
- yourapp/
__init__.py
static/
templates/
home/
control_panel/
admin/
views/
__init__.py
home.py
control_panel.py
admin.py
models.py
- 除了yourapp/views/__init__.py,在yourapp/views/文件夹中
- 的每一个.py文件都是一个蓝图。在yourapp/__init__.py中,
- 我们将加载这些蓝图并在我们的Flask()对象中注册它们。
- 分区式架构
- 在分区式架构中,按照每一部分所属的蓝图来组织你的应用。
- 管理面板的所有的模板,视图和静态文件放在一个文件夹中,
- 用户控制面板的则放在另一个文件夹中。
- yourapp/
__init__.py
admin/
__init__.py
views.py
static/
templates/
home/
__init__.py
views.py
static/
templates/
control_panel/
__init__.py
views.py
static/
templates/
models.py
- 在像上面列举的分区式结构,每一个yourapp/之下的文件夹都是
- 一个独立的蓝图。所有的蓝图通过顶级的__init__.py注册到Flask()中。
- 某一类url添加前缀
- 给一类url添加before_request
基本用法
- 让我们看看来自Facebook例子的一个蓝图的代码:
- facebook/views/profile.py
- from flask import Blueprint, render_template
profile = Blueprint('profile', __name__)
@profile.route('/<user_url_slug>')
def timeline(user_url_slug):
# 做些处理
return render_template('profile/timeline.html')
@profile.route('/<user_url_slug>/photos')
def photos(user_url_slug):
# 做些处理
return render_template('profile/photos.html')
@profile.route('/<user_url_slug>/about')
def about(user_url_slug):
# 做些处理
return render_template('profile/about.html')
- 要想创建一个蓝图对象,你需要importBlueprint()类并用参数name
- import_name初始化。通常用__name__,一个表示当前模块的特殊的
- Python变量,作为import_name的取值。
- 假如使用分区式架构,你得告诉Flask某个蓝图是有着自己的模板和静态文件夹的。
- 下面是这种情况下我们的定义大概的样子:
- profile = Blueprint('profile', __name__,
template_folder='templates',
static_folder='static')
- 现在我们已经定义好了蓝图。是时候向Flask app注册它了
- facebook/__init__.py
- from flask import Flask
from .views.profile import profile
app = Flask(__name__)
app.register_blueprint(profile)
-现在在fackbook/views/profile.py中定义的路径(比如/<user_url_slug>)
会被注册到应用中,就像是被通过@app.route()定义的。
使用一个动态的URL前缀
- 继续看Facebook的例子,注意到所有的个人信息路由都以<user_url_slug>开头
并把它传递给视图函数。我们想要用户通过类似http://facebook.com/john.doe的
URL访问个人信息。通过给所有的蓝图的路由定义一个动态前缀,我们可以结束这种单调
的重复。
- 蓝图允许我们定义静态的或动态的前缀。举个例子,我们可以告诉Flask蓝图中
- 所有的路由应该以/profile作为前缀;这样是一个静态前缀。在Fackbook这个例子中,
- 前缀取决于用户浏览的是谁的个人信息。他们在URL对应片段中输入的文本将决定我们输
- 出的视图;这样是一个动态前缀。
- 我们可以选择何时定义我们的前缀。我们可以在下列两个时机中选择一个定义前缀:
当我们实例化Blueprint()类的时候,或当我们在app.register_blueprint()中注册的时候。
下面我们在实例化的时候设置URL前缀:
facebook/views/profile.py
from flask import Blueprint, render_template
profile = Blueprint('profile', __name__, url_prefix='/<user_url_slug>')
# [...]
下面我们在注册的时候设置URL前缀:
facebook/__init__.py
from flask import Flask
from .views.profile import profile
app = Flask(__name__)
app.register_blueprint(profile, url_prefix='/<user_url_slug>')
- 尽管这两种方式在技术上没有区别,最好还是在注册的同时定义前缀。这使得前缀的定义
可以集中到顶级目录中。因此,我推荐使用url_prefix。
使用一个动态子域名
- 今天,许多SaaS应用提供用户一个子域名来访问他们的软件。举个例子,Harvest,
是一个针对顾问的日程管理软件,它在yourname.harvestapp.com给你提供了一个控制
面板。下面我将展示在Flask中如何像这样自动生成一个子域名。
- 在这一节,我将使用一个允许用户创建自己的网站的应用作为例子。假设我们的应用有
三个蓝图分别针对以下的部分:用户注册的主页面,可用于建立自己的网站的用户管理面板,
用户的网站。考虑到这三个部分相对独立,我们将用分区式结构组织起来。
sitemaker/
__init__.py
home/
__init__.py
views.py
templates/
home/
static/
home/
dash/
__init__.py
views.py
templates/
dash/
static/
dash/
site/
__init__.py
views.py
templates/
site/
static/
site/
models.py