Flask 入门

1. 介绍

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用

wsgiref

最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块

from wsgiref.simple_server import make_server


def mya(environ, start_response):
    print(environ)
    start_response('200 OK', [('Content-Type', 'text/html')])
    if environ.get('PATH_INFO') == '/index':
        with open('templates/index.html', 'rb') as f:
            data = f.read()

    elif environ.get('PATH_INFO') == '/home':
        with open('templates/home.html', 'rb') as f:
            data = f.read()
    else:
        data = b'<h1>Hello, web!</h1>'
    return [data]


if __name__ == '__main__':
    myserver = make_server('', 8010, mya)
    print('监听8010')
    myserver.serve_forever()


# wsgiref简单应用

2. 初步使用

安装:pip3 install flask

from flask import Flask

# 实例化产生一个Flask对象
app = Flask(__name__)
# 将 '/'和视图函数hello_workd的对应关系添加到路由中
@app.route('/') 
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run() # 最终调用了run_simple()
新手四件套:
返回字符串  return 字符串  					django中 HttpResponse('字符串')
返回模板    return render_template 			django中 render(request,模板,{})
返回重定向  return redirect('/login') 		django中 redirect('/login')
返回json   return jsonify(字典,列表)			django中 JsonResponse

3. 配置文件

3.1 配置文件写法

flask 配置文件写法很多种,如下所示:

  1. 第一种:直接配置
app = Flask(__name__)
app.secret_key = 'amsnjabcascasdnknfv'
app.debug = True
  1. 第二种:app 所有的配置项都在 app.config 这个字典中
app = Flask(__name__)
app.config['DEBUG'] = True
  1. 第三种:编写一个 settings.py 文件用于存放配置
# settings.py
NAME = 'xwx'
app = Flask(__name__)
# 通过py文件获取配置
app.config.from_pyfile('settings.py')
print(app.config['NAME'])
  1. 第四种:通过类的方式(常用)

创建 settings.py 文件

# 通用配置类
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'

# 生成配置类
class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

# 开发配置类
class DevelopmentConfig(Config):
    DEBUG = True

使用

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')
print(app.config)
  1. 其他方式
# 通过环境变量配置
app.config.from_envvar("环境变量名称")
# app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
# 环境变量的值为python文件名称名称,内部调用from_pyfile方法
app.config.from_json("json文件名称")
# JSON文件名称,必须是 json 格式,因为内部会执行 json.loads
app.config.from_mapping({'DEBUG': True})
# 字典格式

3.2 默认配置

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:

{
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

4. 路由

django 与 flask 路由的区别:

  • 在django中,路由是浏览器访问服务器时,先访问的项目中的url,再由项目中的url找到应用中url, 这些url是放在一个列表里,遵从从前往后匹配的规则。

  • 在flask中,路由是通过装饰器给每个视图函数 提供的,而且根据请求方式的不同可以一个url用于不同的作用。

4.1 路由典型写法

@app.route('/detail/<int:nid>', methods=['GET'], endpoint='detail')
@app.route('/index', methods=['GET'], endpoint='index')
@loginDecorator
def index():
    return 'xwx'

4.2 路由转换器

from werkzeug.routing import DEFAULT_CONVERTERS

#: the default converter mapping for the map.
DEFAULT_CONVERTERS: t.Mapping[str, t.Type[BaseConverter]] = {
    "default": UnicodeConverter,
    "string": UnicodeConverter,
    "any": AnyConverter,
    "path": PathConverter,
    "int": IntegerConverter,
    "float": FloatConverter,
    "uuid": UUIDConverter,
}
转换器类型数据
defaultUnicodeConverter字符
stringUnicodeConverter字符
anyAnyConverter
pathPathConverter路径
intIntegerConverter整数
floatFloatConverter小数
uuidUUIDConverteruuid

使用

@app.route('/home/<int:uid>', endpoint='home', methods=['GET'])
def home(uid):	# 接收一个参数
    print(uid)
    return render_template('home.html')

4.3 路由源码分析

  • 装饰器分析

@ 是 python 特殊语法糖,会把下面的函数当参数传入。如下有俩个装饰器的情况下,优先执行最上层的装饰器,也就是包在最外层的装饰器。

@app.route('/index', endpoint='index')	# 先执行
@loginDecorator							# 后执行
def index():
    return 'xwx'
  • 源码分析
def route(self, rule: str, **options: t.Any) -> t.Callable:
    def decorator(f: t.Callable) -> t.Callable:
        endpoint = options.pop("endpoint", None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator

# 最终执行的是 add_url_rule 函数

@setupmethod
def add_url_rule(
    self,
    rule: str,
    endpoint: t.Optional[str] = None,
    view_func: t.Optional[t.Callable] = None,
    provide_automatic_options: t.Optional[bool] = None,
    **options: t.Any,
) -> None:
    raise NotImplementedError
  • 参数分析
参数说明
ruleURL规则
view_func视图函数名称
endpoint名称,用于反向生成URL,即: url_for(‘名称’)
methods允许的请求方式,如:[“GET”, “POST”]
strict_slashes对URL最后的 / 符号是否严格要求
redirect_to重定向到指定地址
subdomain子域名访问
defaults默认值, 当URL中无参数,函数需要参数时,使用defaults = {‘k’: ‘v’}为函数提供参数

所以注册路由的另外一种方式是

app.add_url_rule('/order/<string:pk>', view_func=order)
app.add_url_rule('/index', view_func=index,)

5 基于类的视图

class Home(MethodView):
    methods = ['GET']

    # decorators = (装饰器名字,装饰器名字2,)

    def get(self):
        return 'get'

    def post(self):
        return 'post'


app.add_url_rule('/home', view_func=Home.as_view(name='home'))
1. 'as_view' 的name是别名,之前写fbv的时候,endpoint是别名,在cbv中name就是endpoint,但
是必须写,即便写了endpoint
2. 'Home.as_view' 是view函数的内存地址,请求来了执行 self.dispatch_request(),MethodView
重写了dispatch_request,其根据请求方式执行视图类中跟请求方式同名的方法,如果视图类继承了View
需要重写dispatch_request    
3. cbv加装饰器,在类中写 decorators = (装饰器名字1, 装饰器名字2),第一个位置的会放在最下层
多个装饰器执行顺序是从【上往下执行】
4. cbv只允许某个请求方式   methods=['POST']

6. 模板

flask 的模板语法使用第三方 jinja2,兼容 dtl,但是它可以加括号,可以使用 [ ],且处理了xss攻击

6.1 渲染变量、变量的循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.items() %}
        <tr>
            <td>{{k}}</td>
            <td>{{v.name}}</td>
            <td>{{v['name']}}</td>
            <td>{{v.get('name')}}</td>
            <td><a href="/detail/{{k}}">查看详细</a></td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

6.2 逻辑判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% if name %}
          <h1>Hello {{ name }}!</h1>
        {% else %}
          <h1>Hello World!</h1>
        {% endif %}
    </table>
</body>
</html>

6.3 Markup

除了使用 safe 外还可以使用 Markup ,其等价于 django的 mark_safe 。防止 xss 攻击是使用了 html的特殊字符替换(例如将 < 替换成 &lt 、> 替换成 &gt ),但是如果使用了 |safe 或者 Markup ,就不会渲染到页面上

from flask import Flask,render_template,Markup,jsonify,make_response
app = Flask(__name__)

def func1(arg):
    return Markup("<a href="http://www.baidu.com">点我看美女</a>")
    
@app.route('/')
def index():
    return render_template('index.html',ff = func1)

if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    {{ff()}}
	{{ff()|safe}}

</body>
</html>

7. 请求响应

7.1 请求对象的属性和方法

属性说明数值/类型
request.method请求方式str
request.argsget 请求参数ImmutableMultiDict([])
request.formpost 提交的数据ImmutableMultiDict([])
request.valuesget,post提交的数据总和CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([])])
request.cookiescookies
request.headers请求头(等同于django的META)<class ‘werkzeug.datastructures.EnvironHeaders’>
request.path路径/home
request.full_path全路径/home?name=xwx
request.script_root
request.url带域名带参数的请求路径http://127.0.0.1:5000/home?name=xwx
request.base_url带域名请求路径http://127.0.0.1:5000/home
request.url_root域名+端口http://127.0.0.1:5000/
request.host_url域名+端口http://127.0.0.1:5000/
request.host不带http的域名+端口127.0.0.1:5000
request.files文件ImmutableMultiDict([(‘files’, <FileStorage: ‘20200917170453_31512.jpeg’ (‘image/jpeg’)>)]) <class ‘werkzeug.datastructures.ImmutableMultiDict’>
request.files.get(‘files’)文件<class ‘werkzeug.datastructures.FileStorage’>

7.2 响应对象的属性和方法

属性说明
“字符串”返回字符串
render_template(‘html模板路径’,**{})返回模板
redirect重定向
jsonify返回 JSON 数据

8. cookie、session

cookie:存放在客户端的键值对
session:存放在客户端的键值对
token:存放在客户端,通过算法来校验

8.1 添加 cookie、session

  • cookie
    使用 make_response 包裹响应对象
response = make_response(render_template('index.html'))
 # response 是 flask.wrappers.Response类型
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value' # 可用于跨域
return response
  • session
    from flask import session
    除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。 (app.session_interface对象)
设置:session['username']'xxx'
删除:session.pop('username', None)

在使用 session 之前必须现在设置一下密钥 secret_key

app.secret_key="asdas"   # 值随便
  • django 与 flask 的不同
在django中
1. 生成一个随机的字符串 
2. 往数据库存 
3. 写入cookie返回浏览器

在 flask 中他没有数据库,但 session 是怎样实现的?
1. 生成一个密钥写入这个cookie
2. 然后下次请求的时候,通过这个cookie解密,然后赋值给session
#可以通过 app.session_interface 来查看

8.2 flask 的 session 源码分析

  1. app.session_interface 起手
session_interface = SecureCookieSessionInterface()
# 发现 session_interface 是 SecureCookieSessionInterface 的对象。
# 该类中有 open_session、save_session 方法
  1. open_session 方法

open_session方法当请求来了,从cookie中取出字符串,把字符串反序列化成session对象

def open_session(
    self, app: "Flask", request: "Request"
) -> t.Optional[SecureCookieSession]:
    s = self.get_signing_serializer(app)
    if s is None:
        return None
    val = request.cookies.get(self.get_cookie_name(app))
    if not val:
        return self.session_class()
    max_age = int(app.permanent_session_lifetime.total_seconds())
    try:
        data = s.loads(val, max_age=max_age)
        return self.session_class(data)
    except BadSignature:
        return self.session_class()
# 从 cookie 中取出字符串
val = request.cookies.get(self.get_cookie_name(app))
# get_cookie_name 获取的是 SESSION_COOKIE_NAME 默认配置的 session 键名,可以修改

# 反序列化成 session 对象
data = s.loads(val, max_age=max_age)
  1. save_session

save_session 方法请求走了,把 session 对象,序列化成字符串,放到 cookie 中

def save_session(
    self, app: "Flask", session: SessionMixin, response: "Response"
) -> None:
    name = self.get_cookie_name(app)
    domain = self.get_cookie_domain(app)
    path = self.get_cookie_path(app)
    secure = self.get_cookie_secure(app)
    samesite = self.get_cookie_samesite(app)
    
    if not session:
        if session.modified:
            response.delete_cookie(
                name, domain=domain, path=path, secure=secure, samesite=samesite
            )
        return
        
    if session.accessed:
        response.vary.add("Cookie")
    if not self.should_set_cookie(app, session):
        return

    httponly = self.get_cookie_httponly(app)
    expires = self.get_expiration_time(app, session)
    val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
    # 设置 cookie 
    response.set_cookie(
        name,
        val,  # type: ignore
        expires=expires,
        httponly=httponly,
        domain=domain,
        path=path,
        secure=secure,
        samesite=samesite,
    )
  1. app.session_interface 中 save_session 的参数(设置cookie的参数)
参数说明
key
value
max_age=None超时时间 cookie需要延续的时间(以秒为单位)如果参数是 None ,这个cookie会延续到浏览器关闭为止
expires=None超时时间(IE requires expires, so set it if hasn’t been already.)
path=‘/’Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
domain=NoneCookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
secure=False浏览器将通过HTTPS来回传cookie
httponly=False只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

9. 闪现 message

闪现是由 flash 翻译过来的。一般用在当 a 页面操作出错,跳转到 b 页面,在 b 页面显示 a 页面的错误信息。其本质就是放到session中,等同于 django 的 message 框架

基础使用

设置: flash()
取值: get_flashed_message()
from flask import Flask, flash, get_flashed_messages, redirect

app = Flask(__name__)
app.secret_key = 'asdfasdf'
app.debug = True


@app.route('/index')
def index():
	# flash('超时错误')
	# 添加分类
    flash('超时错误', category="x1")
    return redirect('/error')

@app.route('/error')
def error():
    """
    展示错误信息
    :return:
    如果get_flashed_messages(with_category=True)
    """
    # msg = get_flashed_messages()
    # 添加分类,取出的值是列表
    msg = get_flashed_messages(category_filter=['x1'])    
    return "错误信息:%s" % msg[0]

if __name__ == '__main__':
    app.run()

注意点: 在一次请求中,把一些数据放在闪现中,下次请求就可以从闪现中取出来,取一次就没了(使用分类也是这样)

10. 请求扩展

10.1 before_request

类比 django 中间件中的 process_request,在请求收到之前绑定一个函数做一些事情
若其返回的是响应对象,则不继续往下走了,如果返回 None,继续走下一个请求扩展

  • 请求来了,就会执行它
  • 多个 before_request,会从上往下依次执行
# 基于它做用户登录认证
@app.before_request
def process_request(*args, **kwargs):
    if request.path == '/login':
        return None
    try:
        session['user_info']
        return None
    except KeyError as e:
        return redirect('/login')

10.2 after_request

类比 django 中间件中的 process_response,每一个请求之后绑定一个函数,如果请求没有异常

  • 必须返回 response 对象
  • 请求走了,会执行它
  • 多个 after_request,从下往上依次执行
@app.after_request
def p1(response):
    print(111)
    print(response)
    return response


@app.after_request
def p2(response):
    print(222)
    print(response)
    return response


输出:
>> 222
>> <Response 5 bytes [200 OK]>
>> 111
>> <Response 5 bytes [200 OK]>

10.3 before_first_request

启动后第一次请求时,跟浏览器无关。返回 None,会继续往下执行

@app.before_first_request
def first():
    pass

10.4 teardown_request

每一个请求之后绑定一个函数,即使遇到了异常。无论程序是否出异常,都会触发它,可以用来记录错误日志

@app.teardown_request
def ter(e):
	# 打印的错误信息,注意需要将 debug 设置为 False
    print(e)
    return None

10.5 errorhandler

监听某个状态码,如果是这个状态码的错误,就会触发它的执行。可以返回响应对象例如 404 界面

@app.errorhandler(404)
def error_404(e):
	# 错误信息
    print(e)
    return '该页面不存在'

10.6 template_global

标签

@app.template_global()
def add(a, b):
    return a + b

# 在模板中使用 {{add(1,2)}}

10.7 template_filter

过滤器

@app.template_filter()
def add(a, b):
    return a + b

# 在模板中使用 {{3|add(1)}}

10.8 总结

1 重点掌握before_request和after_request,

2 注意有多个的情况,执行顺序

3 before_request请求拦截后(也就是有return值),response所有都执行

@app.before_request
def req1():
    print('这是请求1')
    return '这是请求1'

@app.before_request
def req2():
    print('这是请求2')
    return '这是请求2'

@app.after_request
def res1(response):
    print('这是响应1')
    return response

@app.after_request
def res2(response):
    print('这是响应2')
    return response


输出:
>> 这是请求1
>> 这是响应2
>> 这是响应1

11. 蓝图

蓝图是由 Blue_print 翻译过来的,作用是对目录进行划分

11.1 使用蓝图之中小型系统

目录结构:

flaskProject					# 项目名
	flaskProject				# 包名
		static					# 静态文件夹
		templates				# 模板文件夹
		views					# 视图函数文件夹
			user.py				# 用户相关视图函数
			goods.py			# 商品相关视图函数
		__init__.py				# 包 init 文件
	run.py						# 项目启动文件
  • _init_
from flask import Flask
from flaskProject.views import user
from flaskProject.views import goods

# 注册app,指定模板文件路径、静态文件路径以及路径后缀
app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/static')

# 在app中注册蓝图
app.register_blueprint(user.user)
app.register_blueprint(goods.good)
  • user.py
from flask import Blueprint

user = Blueprint('user', __name__)

# 使用蓝图注册路由
@user.route('/login')
def login():
    return 'login'
  • run.py
from flaskProject import app

if __name__ == '__main__':
	# 指定运行的IP与端口
    app.run(host='0.0.0.0', port=8080)

11.2 使用蓝图之大型系统

目录结构:

flaskProject_big						# 项目名
	flaskProject_big					# 包名 
		goods							# app 名
			static						# app 独立静态文件
			templates					# app 独立模板
			__init__.py					# app 双下 init
			views.py					# app 独立视图函数
			
		user							# app 名
			static						# app 独立静态文件
			templates					# app 独立模板
			__init__.py					# app 双下 init
			views.py					# app 独立视图函数
			
		__init__.py						# 包 双下init
	run.py								# 启动文件
  • flaskProject_big/user/init.py
from flask import Blueprint

# 第一步:初始化蓝图
user = Blueprint(
    'user',
    __name__,
    template_folder='templates',  # 指定该蓝图对象自己的模板文件路径
    static_folder='static',  	  # 指定该蓝图对象自己的静态文件路径
    static_url_path='/static',
)

# 导入视图后路由才能被匹配,且不能放在前面导入
from . import views
  • flaskProject_big/user/views.py
# 导入蓝图
from . import user
from flask import render_template

@user.before_request
def before():
    print('user 的 before')

# 第三步:使用蓝图注册路由
@user.route('/login')
def login():
    return render_template('login.html')
  • flaskProject_big/user/templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<body>
<img src="static/m.jpeg">
</body>
</html>
  • flaskProject_big/init.py
from flask import Flask
from .goods import goods
from .user import user

app = Flask(__name__)
app.debug = True

# 第二步:在app中注册蓝图
# url_prefix='/user' 设置访问这个app的前缀,等同于django include
app.register_blueprint(user, url_prefix='/user')  
app.register_blueprint(goods)
  • run.py
from flaskProject_big import app

if __name__ == '__main__':
    app.run(port=8080)

总结:

  • 第一步,在 app 的双下 init 中初始化蓝图,并导入视图
  • 第二步,在 包 的双下 init 中注册蓝图,可以设置 url_prefix 路由前缀
  • 第三步,在 app 的视图文件中注册路由,编写视图函数即可

注意点:

  • 加了 url_prefix (蓝图URL前缀)后,在该蓝图下所有 url 都加前缀
  • 初始化蓝图时,template_folder 给当前蓝图单独使用 templates,若当前找不到,会向上查找,找总templates
  • 蓝图的请求拓展例如 befort_request,只对当前蓝图有效
  • 大型项目,可以模拟出类似于 django 中 app 的概念

12. g 对象

专门用来存储用户信息的g对象,g的全称的为global。不放在 request中是为了防止值被覆盖掉

# 请求拓展
@user.before_request
def before():
    g.name = 'xwx'

@user.route('/login')
def login():
    print(g.name, type(g))
    return render_template('login.html')

输出:
>> xwx <class 'werkzeug.local.LocalProxy'>

g 对象和 session 的区别

  • session 对象是可以跨 request 的,只要 session 还未失效,不同的 request 的请求会获取到同一个 session
  • 但是 g 对象不是,g 对象不需要管过期时间,请求一次就 g 对象就改变了一次,或者重新赋值了一次,也就是 g 对象只对当次请求有效

13. flask-session

session 默认以 cookie 的形式放到浏览器中,若把 session 放到服务端保存( redis 、mysql 中等等)

作用:将默认保存的签名 cookie 中的值保存到 redis/memcached/file/Mongodb/SQLAlchemy
安装:pip3 install flask-session

Django 存放到 redist 参考:https://blog.csdn.net/weixin_42194215/article/details/111414823

13.1 使用方式一

from flask import Flask,session
from flask_session import RedisSessionInterface
import redis

app = Flask(__name__)

conn=redis.Redis(host='127.0.0.1',port=6379)
# key_prefix 表示在 redis 的前缀
app.session_interface=RedisSessionInterface(conn,key_prefix='xwx_')

@app.route('/')
def hello_world():
    session['name']='xwx'
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

13.2 使用的方式二

from redis import Redis
from flask_session import Session
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
# 用类包裹,常见写法
Session(app)

问题:设置cookie时,如何设定关闭浏览器则cookie失效。

response.set_cookie('k','v',exipre=None)#这样设置即可
#在session中设置
app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False)
#一般不用,我们一般都设置超时时间,多长时间后失效

问题:cookie默认超时时间是多少?如何设置超时时间

#源码expires = self.get_expiration_time(app, session)
'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),#这个配置文件控制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值