FLASK总结之一

简介: FLASK总结之一

一、配置文件

1.1 默认配置

flask支持多种方式进行配置项的新增和修改,默认配置项如下。同 django框架大差不差

```python
{        
        '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,
}
配置项的加载与使用
from  flask import Flask,jsonify
app=Flask(__name__)
# 方式一:直接配置--->能够配的参数少
app.secret_key='asdfasdf'   # secret_key 用来加密解密的密钥 
app.debug=True          # 修改了代码,只需要保存,自动热加载
# 方式二:通过app.config字典,配置,这个字典中放了所有的配置
app.config['DEBUG']=False # 都要大写
app.config['MYSQL_HOST'] = '127.0.0.1'
# 方式三:通过settings.py 配置文件--->用得少,django 框架的使用方式
app.config.from_pyfile("settings.py")
# 方式四:通过类来加载对象
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'
    
app.config.from_object("Config")
# 方式五:通过加载json格式配置文件
app.config.from_json("settings.json")
# 方式六:通过环境变量配置
app.config.from_envvar("环境变量名称")
# 方式七:服务(项目)多了,配置文件多了---》配置中心 nacos 阿波罗
m={}
m=request.get('url')  # m的值是dict类型 
app.config.from_mapping(m)

二、路由系统

@app.route(‘/detail/int:nid’,methods=[‘GET’],endpoint=‘detail’)

2.1 路由本质

django 中的路由在 urls.py 文件中进行管理 flask 中路由基于装饰器进行管理。实际上,无论是在django 还是 flask 中,只要你愿意,咋样都行

flask 注册路由的两种方式:

1. @app.router('/')  #推荐使用
   def index():
        ...
2. app.add_url_rule('/', view_func=index)
app.router()
#--->本质上就是self.add_url_rule,self就是flask对象app  
2.2 CBV写法

在flask 中,cbv 可以选择继承 View (django 继承的是View) 和 MethodView 两个类

如果继承 View 类,需要重写 dispatch 方法

如果继承 MethodView 类,直接写 get , post 方法即可

class HomeView(MethodView):
    methods = ['GET']   # 允许请求方式
    decorators = [auth, ]  # 加载装饰器
    
    
    def get(self):
        print(request.path)
        return 'cbv的homeview'
# 添加路由
# name 是路由别名,跟endpoint一个作用,但是cbv必须传name 
# 也可将路由的加载放在类中
app.add_url_rule('/home',view_func=HomeView.as_view(name='home'))
2.3 路由的参数

app.add_url_rule的参数

1 rule, URL规则,  可以使用转换器 <int:pk>
2 endpoint, 当前路由的别名,如果不传, 默认已函数名作为endpoint,如果函数名重名,就会有两个    重名的地址,报错,主要用来反向解析
    源码:  endpoint = _endpoint_from_view_func(view_func)
    用于反向生成URL,即: url_for('名称')  # url_for 通过 endpoint 的值反向解析出 url
    多个视图函数,如果加同一个装饰器,如果不写endpoint,就会报错 
 
3 view_func, 视图函数名称 如果是cbv  视图类.as_view(name='xx')
4 defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
为函数提供参数,就是django中的kwargs
5 methods = None, 允许的请求方式,如:["GET", "POST"]
6 strict_slashes = None
对URL最后的 / 符号是否严格要求
7 redirect_to = None,   redirect_to='/home'
#重定向到指定地址
8 子域名访问
subdomain = None, 
2.4 请求与响应

请求

# http请求中有的东西,都能取出来
print(request.method)
# request.method  提交的方法
# request.args  get请求提及的数据
print(request.args)
# request.form   post请求提交的数据
print(request.form)
# request.values  post和get提交的数据总和
print(request.values)
# request.cookies  客户端所带的cookie
print(request.cookies)
# request.headers  请求头
print(request.headers)
# request.path     不带域名,请求路径
print(request.path)
# request.full_path  不带域名,带参数的请求路径
print(request.full_path)
# request.url           带域名带参数的请求路径
print(request.url)
# request.base_url      带域名请求路径
# request.url_root      域名
# request.host_url      域名
# request.host          127.0.0.1:500
print(request.host)  
# request.files    接受文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename))

响应

# 4 件套
return "字符串"  # 放回字符串
return render_template('html模板路径',**{})   # 返回html文件
return redirect('/index.html')    # 重定向
return jsonify({'k1':'v1'})     # json 格式字符串    
# 响应头中加东西,四件套都可以使用make_response包裹成响应对象,等同于django中的HTTPResponse
res=make_response('字符串')
res.headers['name']='yxh'
return res
# 设置cookie
response = make_response('字符串')
response.set_cookie('key', 'value')
return response

session

cookie:存放在客户端的键值对
session:存放在客户端的键值对
token:存放在客户端,通过算法来校验
在使用session之前必须现在设置一下密钥
app.secret_key="asdas" # 值随便写

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。 (app.session_interface对象)

设置:session[‘username’] = ‘xxx’

# 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
# 在flask中他没有数据库,但session是怎样实现的?
    # 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
    # 我们通过app.session_interface来查看
  
删除:session.pop('username', None)
app.session_interface中save_session的参数(设置cookie的参数)
源码:
    response.set_cookie(
        name,
        val,  # type: ignore
        expires=expires,
        httponly=httponly,
        domain=domain,
        path=path,
        secure=secure,
        samesite=samesite,
    )
name, 键
val , 值
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
                   
domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取                
path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
secure=False, 浏览器将通过HTTPS来回传cookie
samesite=None  将cookie的范围限制为仅附加到“相同站点”的请求
session源码的执行流程
处理session,有个一个类SecureCookieSessionInterface(),有俩重要方法 
-save_seesion
    1 把sesion对象,当字典 转成字符串,使用秘钥加密 
        val = self.get_signing_serializer(app).dumps(dict(session))
    2 写入cookie返回浏览器 session=加密的字符串
        response.set_cookie(
                app.session_cookie_name,
                val, # 加密字符串 
        )
-open_session
    1 根据sessionid取出加密字符串
          val = request.cookies.get(app.session_cookie_name)
    2 通过秘钥解密,组装成 session
          data = s.loads(val, max_age=max_age)
          self.session_class(data)
    3 在视图函数中才能正常使用session['name']取值,赋值,删除值
    
 可以自定义一个类SecureCookieSessionInterface,重写open_session和save_session,把session存到数据库,redis里
2.5 闪现(django 中 message)
-设置: flash('aaa')
-取值:get_flashed_message()
-
-假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
# 本质:
如果在同一次请求中,放到request对象中即可
如果在不同请求中,放到session中,所以使用闪现一定配置秘钥
# 使用
设置:flash('诱惑美女')
获取:res=get_flashed_messages()
设置:
flash('美女',category='man')
flash('帅哥',category='wonmen')
获取:
res=get_flashed_messages(with_categories=True,category_filter=["man"])
demo
@app.route('/index')
def index():
    # 从某个地方获取设置过的所有值,并清除。
    val = request.args.get('v')
    if val == 'oldboy':
        return 'Hello World!'
    flash('超时错误',category="x1")
    return "ssdsdsdfsd"
    # return redirect('/error')
@app.route('/error')
def error():
    """
    展示错误信息
    :return:
    如果get_flashed_messages(with_category=True)
    """
    data = get_flashed_messages(category_filter=['x1'])
    if data:
        msg = data[0]
    else:
        msg = "..."
    return "错误信息:%s" %(msg,)
if __name__ == '__main__':
    app.run()
2.6 请求扩展

和django中间件差不多的玩意,但是可以通过蓝图定义给部分接口使用

1 before_request
类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情
# 基于它做用户登录认证
@app.before_request
def process_request(*args,**kwargs):
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if user:
        return None
    return redirect('/login')
2 after_request
类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常
@app.after_request
def process_response1(response):
    print('process_response1 走了')
    return response
3 before_first_request
第一次请求时,跟浏览器无关
@app.before_first_request
def first():
    pass
4 teardown_request
每一个请求之后绑定一个函数,即使遇到了异常
@app.teardown_request 
def ter(e):
    pass
5 errorhandler
路径不存在时404,服务器内部错误500
@app.errorhandler(404)
def error_404(arg):
    return "404错误了"
6 template_global
标签
@app.template_global()
def sb(a1, a2):
    return a1 + a2
# {{sb(1,2)}}
7 template_filter
过滤器
@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3
# {{ 1|db(2,3)}}
总结:
    1 重点掌握before_request和after_request,
    2 注意有多个的情况,执行顺序
    3 before_request请求拦截后(也就是有return值),response所有都执行
2.7 flask 中间件
flask 中间件 和 before_request 和 after_request 实现效果类似。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
    return 'Hello World!'
# 模拟中间件
class Md(object):
    def __init__(self,old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app
    def __call__(self,  environ, start_response):
        print('开始之前')  
        ret = self.old_wsgi_app(environ, start_response)
        print('结束之后')
        return ret
if __name__ == '__main__':
    # 1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法    
    # 2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
    # 3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
    # 4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
    # 把原来的wsgi_app替换为自定义的,
    
    app.wsgi_app = Md(app.wsgi_app)
    app.run()
2.8 蓝图

视图是一个应用对请求进行响应的函数。 Flask 通过模型把进来的请求 URL 匹配到 对应的处理视图。视图返回数据, Flask 把数据变成出去的响应。 Flask 也可以反 过来,根据视图的名称和参数生成 URL 。

简单点说就是对 不同 app进行路由管理,当前蓝图下的请求扩展只对当前蓝图有效。

# 第一步:定义蓝图对象
user = Blueprint('user', __name__)
# 第二步:使用蓝图写路径,写请求扩展(只针对于当前蓝图生效)
@user.route('/index')
# 第三步:把蓝图注册进app中
app.register_blueprint(user)

使用蓝图结构案例

目录结构:

-flask_pro
    -flask_test
        -__init__.py
        -static
        -templates
        -views
            -order.py
            -user.py
     -manage.py 
        
_init.py
from flask import  Flask
app=Flask(__name__)
from flask_test.views import user
from flask_test.views import order
app.register_blueprint(user.us)
app.register_blueprint(order.ord)
manage.py
from flask_test import  app
if __name__ == '__main__':
    app.run(port=8008)
user.py
from flask import Blueprint
us=Blueprint('user',__name__)
@us.route('/login')
def login():
    return 'login'
order.py
from flask import Blueprint
ord=Blueprint('order',__name__)
@ord.route('/test')
def test():
    return 'order test'

总结:

  • xxx = Blueprint(‘account’, name,url_prefix=‘/xxx’) :蓝图URL前缀,表示url的前缀,在该蓝图下所有url都加前缀
  • xxx = Blueprint(‘account’,name,url_prefix=‘/xxx’,template_folder=‘tpls’):给当前蓝图单独使用templates,向上查找,当前找不到,会找总templates
  • 蓝图的befort_request,对当前蓝图有效
  • 大型项目,可以模拟出类似于django中app的概念
  • g对象 是global的缩写,类似于 django 框架中的 request.context 属性。目的都是为了在不污染 request 对象前提下,实现在同一个请求中,传递数据,上下文传递,赋值取值只针对于当次请求生效。
from flask import g
# 设置值
g.name = "yxh"
# 取值
name = g.name  
name = g.get("name")
from flask import Flask, g
app = Flask(__name__)
def test_g():
    print(g.get('name', None))
    g.name = '李四'
@app.route('/test')
def test():
    g.name = '张三'
    test_g()  # 控制台会打印'张三'
    print(g.name)  # 李四
    return 'test'
if __name__ == '__main__':
    app.run()
2.9 g对象和session的区别

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

相关文章
|
4天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
6天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1558 10
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
10天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
687 26
|
6天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
219 3
|
1天前
|
Python
【10月更文挑战第10天】「Mac上学Python 19」小学奥数篇5 - 圆和矩形的面积计算
本篇将通过 Python 和 Cangjie 双语解决简单的几何问题:计算圆的面积和矩形的面积。通过这道题,学生将掌握如何使用公式解决几何问题,并学会用编程实现数学公式。
103 59
|
13天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
704 5
|
2天前
|
Java 开发者
【编程进阶知识】《Java 文件复制魔法:FileReader/FileWriter 的奇妙之旅》
本文深入探讨了如何使用 Java 中的 FileReader 和 FileWriter 进行文件复制操作,包括按字符和字符数组复制。通过详细讲解、代码示例和流程图,帮助读者掌握这一重要技能,提升 Java 编程能力。适合初学者和进阶开发者阅读。
101 61
|
13天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
3天前
vue3+Ts 二次封装ElementUI form表单
【10月更文挑战第8天】
110 57