wsgi
是什么?
全称 web服务器网关接口,是为python语言定义的web服务器和web应用程序活框架之间的一种简单而通用的接口。
自从wsgi被开发出来以后,许多其他语言也出现了类似接口。
发展背景
以前如何选择合适的web应用程序框架成为困扰python初学者的一个问题,
这是因为,一般而言,web应用程序框架的选择将限制可用的web服务器的选择,反之亦然,
那时的python应用程序通常是为 cgi fastcgi mod_python 中的一个设计
甚至是为特定web服务器的自定义的api接口设计的
作用
wsgi是作为服务器与web应用程序或应用框架之间的一种低级别的接口,可提升可移植web应用开发的共同点,wsgi是基于现存的cgi标准而设计的
wsgi相当于webserver 和 applicaion 中间的一个桥梁 主要是用来动态处理页面请求
MVC
组成
model
view  返回内容展示
control 视图函数
控制器 controller 负责转发请求,对请求机型处理
视图 view 界面设计人员进行图形界面设计
模型 model 程序员编写程序应有的功能,实现算法等等
DBA 进行数据管理和数据库设计(以实现具体功能
view ——通过url—->control——解析请求数据——>model———>DB
回显到视图<——-构建响应数据——-control<———返回操作结果—-model
这是一种分层设计思想,解耦合,方便进行调试,扩展
Flask初始化
from flask import Flask,request,render_templateapp = Flask(__name__,# import_name,static_url_path=None, # url必须“/”开头,从前端访问static文件的时候# 告诉用户访问路径,static_folder="static", # 静态文件存放目录,并不是每次都去访问static的文件 ,浏览器会缓存static_host=None,host_matching=False, # 服务器匹配subdomain_matching=False, # 子域名template_folder="html_file", # 模板存放目录,这些都是可以设置的属性instance_path=None,instance_relative_config=False,root_path=None,)# request 会保存所有页面传来的参数,通过request.args来进行获取# 为一个字典类型,可以通过get方法,或者键值对进行值获取,推荐使用get方法# render_template 返回某个页面的时候使用,后续深入讲解
核心函数流程
# 简单实例flask# 1,初始化 app核心对象 2,添加路由,编写视图函数 3,启动app = Flask(__name__,# 若干属性配置)@app.route('/hello')@app.route('/index') # hello,如果想要多个路径套用同一个视图的情况下,可以直接加注解叠加@app.route("/") # 添加访问路径def home(): # 多路径套用同一个视图 但是一个url不会对应多个视图函数# 视图函数内部要编写的内容# 1.接收参数# 2.调用对应的函数去处理数据# 3.构建响应结果return render_template('index.html')# 启动 ,执行的时候将app.run写在main下面,保证导入的时候不会出错# 其作用是只在本py文件下进行运动if __name__ == '__main__':app.run(port=app.config['PORT'],debug=app.config['DEBUG'])
Flask中运行服务器的两种方式
app.run()启动
命令行方式启动 set FLASK_APP = 设定的app的py文件 || flask run
给视图函数添加装饰器进行扩展的时候的坑
1,除了@app.route()路由装饰器,其他的装饰器必须放在其下main
原因与app.route()的生命周期相关,
2,装饰器返回值必须是视图函数的返回值
当装饰器编写有误的时候,直接原因是装饰器没有返回对象,而app.route()需要使用装饰器的返回对象并将其包装成一个响应结果
Flask的配置文件
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,}
1,通过对象属性赋值配置
app.config['DEBUG'] = True#由于Config对象本质上是字典,所以还可以使用app.config.update(DEBUG=True)
2,通过py文件设置
#通过py文件配置app.config.from_pyfile("python文件名称")如:settings.pyDEBUG = Trueapp.config.from_pyfile("settings.py")#通过环境变量配置app.config.from_envvar("环境变量名称")#app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])环境变量的值为python文件名称名称,内部调用from_pyfile方法app.config.from_json("json文件名称")JSON文件名称,必须是json格式,因为内部会执行json.loadsapp.config.from_mapping({'DEBUG': True})字典格式app.config.from_object("python类或类的路径")app.config.from_object('pro_flask.settings.TestingConfig')settings.pyclass Config(object):DEBUG = FalseTESTING = FalseDATABASE_URI = 'sqlite://:memory:'class ProductionConfig(Config):DATABASE_URI = 'mysql://user@localhost/foo'class DevelopmentConfig(Config):DEBUG = Trueclass TestingConfig(Config):TESTING = TruePS: 从sys.path中已经存在路径开始写PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录(Flask对象init方法的参数)
多url的路由
一个试图函数可以设置多个url路径去访问
一个url路径只可以又一个试图函数
装饰器与路由注解
视图装饰器应当放在最外层,否则里面的装饰器不会生效
视图函数包裹的装饰器不要return值,否则会被包装成返回对象,视图函数中的返回响应对象就不会生效了
# 写个装饰器import timedef log_time(func):def decorator(*args,**kwargs):print(F"{time.time()}")return func(*args,**kwargs)return decorator# 添加路由 视图函数@log_time # 放在这里的话装饰器不会被运行@app.route('/index') # hello,如果想要多个路径套用同一个视图的情况下,可以直接加注解叠加# 应当将扩展的装饰器放在这里def home(): # 多路径套用同一个视图 但是一个url不会对应多个视图函数# 1.接收参数# 2.调用对应的函数去处理数据# 3.构建响应结果return render_template('index.html')
路由参数化
主要有两种方式实现
1,直接从url中获取并传到视图函数中进行处理,并且可以对参数部分进行类型限制
@app.route('/cases/<id>')def index(id):return F"{id}hello addicated"
2,第二种,通过request.args的get方法取到值,视图函数中将不再接收形参
@app.route('/cases')def index1():id = request.args.get('id')return F"{id}hello addicated"
路由注册机制
1,集中注册机制
views.pydef index():reutrn "这是集中注册机制去注册路由"app.add_url_rule('/index',view_func=views.index)
2,注解注册
@app.route("/index")def index():return "这是装饰器注册路由"
app.url_map
flask中专门用来存放url路径与视图函数绑定关系的一个属性
可以体现出路径与视图函数的绑定关系
实例
print(app.url_map)Map([<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])注册之前只有一个static/filenamefilename 可变参数,路由: url 视图函数的绑定关系, static 是端点名称print(app.url_map)Map([<Rule '/hello' (HEAD, GET, OPTIONS) -> test>,test 是端点名称,如果不进行修改,默认为视图函数的名称# 端点名称可更改,在路由进行注册的时候可以通过属性赋值的方式进行更改# HEAD,GET,OPTIONS 是允许的请求方式,在路由注册时可以更改
app.rouet()可配置的参数
methods 限制路由的访问方式
@app.route('/hello',methods=['POST'],endpoint='测试命名')# 注解方式注册路由配置methodsapp.add_url_rule('/hello', view_func=test,methods=['POST'])# 集中式注册机制中对methods设置
endpoint 端点命名
@app.route('/hello',methods=['POST'],endpoint='测试命名')app.add_url_rule('/hello', view_func=test,methods=['POST'],endpoint="测试命名")
redirect_to
由编写方式不同成为两种状态
1,直接在 route参数内些重定向地址,配置地址,这种配置方法将直接跳过本视图函数的处理,直接返回给重定向的目标视图函数
@app.route('/hello',methods=['POST'],endpoint='测试命名',redirect_to='/')
2,在视图函数返回值的时候书写,这种方式会在完成本视图的函数处理之后再进行重定向到目标页面
@app.route('/cases')def index1():id = request.args.get('id')return redirect('/')
defaults
默认值设定,在设计路由参数化的案例中,有的时候需要给一个属性赋一个默认值,
同样根据路由注册方式不偶那个,有两种方式,效果一样
1,在route()参数中去设置,字典 kv对应形式
@app.route('/hello',methods=['POST'],endpoint='测试命名',redirect_to='/',defaults={'id':3})
2,在视图函数中的形参上设置
@app.route('/cases/<id>')def index(id=3): # 直接在形参处进行配置,简洁明了return F"{id}hello addicated"
Flask,大型项目作业时候注意的坑
视图函数的分离
背景:随着项目增大,吧视图函数单独放在一起,不将项目启动,注册路由,视图函数都放一个文件中,会出现分层的需要。所以项目结构会发生改变。
启动文件
视图函数
数据处理
views
其他的帮助函数
views.py 视图层def index():return 'home'def case():return 'cases'urls.py 路由分发层from py_day23 import viewsfrom py_day23.py_day23_2 import appapp.add_url_rule('/',view_func=views.index)app.add_url_rule('/case',view_func=views.case,methods=['POST'])run_app.py 启动层from flask import Flask, requestapp = Flask(__name__)if __name__ == '__main__':app.run(debug=True)
在这样分层的时候,很容出现的一个问题是,循环导入。因为平常的编写习惯,
很容将需要用到的包一股脑的全在项目文件头部进行一次性导入,这样当引用出现交叉时,
极易出现循环导入,而又难以去分析错误成因。
最好的方式是在编写大型项目的时候,用到什么就导入什么,不要偷懒一次性导入
并且在导入的时候不要导入模块,而是用到什么代码就导入模块下的代码,* 也是可以进行使用的
