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初始化

  1. from flask import Flask,request,render_template
  2. app = Flask(
  3. __name__,
  4. # import_name,
  5. static_url_path=None, # url必须“/”开头,从前端访问static文件的时候
  6. # 告诉用户访问路径,
  7. static_folder="static", # 静态文件存放目录,并不是每次都去访问static的文件 ,浏览器会缓存
  8. static_host=None,
  9. host_matching=False, # 服务器匹配
  10. subdomain_matching=False, # 子域名
  11. template_folder="html_file", # 模板存放目录,这些都是可以设置的属性
  12. instance_path=None,
  13. instance_relative_config=False,
  14. root_path=None,
  15. )
  16. # request 会保存所有页面传来的参数,通过request.args来进行获取
  17. # 为一个字典类型,可以通过get方法,或者键值对进行值获取,推荐使用get方法
  18. # render_template 返回某个页面的时候使用,后续深入讲解

核心函数流程

  1. # 简单实例flask
  2. # 1,初始化 app核心对象 2,添加路由,编写视图函数 3,启动
  3. app = Flask(
  4. __name__,
  5. # 若干属性配置
  6. )
  7. @app.route('/hello')
  8. @app.route('/index') # hello,如果想要多个路径套用同一个视图的情况下,可以直接加注解叠加
  9. @app.route("/") # 添加访问路径
  10. def home(): # 多路径套用同一个视图 但是一个url不会对应多个视图函数
  11. # 视图函数内部要编写的内容
  12. # 1.接收参数
  13. # 2.调用对应的函数去处理数据
  14. # 3.构建响应结果
  15. return render_template('index.html')
  16. # 启动 ,执行的时候将app.run写在main下面,保证导入的时候不会出错
  17. # 其作用是只在本py文件下进行运动
  18. if __name__ == '__main__':
  19. app.run(port=app.config['PORT'],
  20. debug=app.config['DEBUG']
  21. )

Flask中运行服务器的两种方式

app.run()启动

命令行方式启动 set FLASK_APP = 设定的app的py文件 || flask run

flask help 可以查看命令帮助

给视图函数添加装饰器进行扩展的时候的坑

1,除了@app.route()路由装饰器,其他的装饰器必须放在其下main
原因与app.route()的生命周期相关,
2,装饰器返回值必须是视图函数的返回值
当装饰器编写有误的时候,直接原因是装饰器没有返回对象,而app.route()需要使用装饰器的返回对象并将其包装成一个响应结果

Flask的配置文件

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

  1. {
  2. 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式
  3. 'TESTING': False, 是否开启测试模式
  4. 'PROPAGATE_EXCEPTIONS': None,
  5. 'PRESERVE_CONTEXT_ON_EXCEPTION': None,
  6. 'SECRET_KEY': None,
  7. 'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
  8. 'USE_X_SENDFILE': False,
  9. 'LOGGER_NAME': None,
  10. 'LOGGER_HANDLER_POLICY': 'always',
  11. 'SERVER_NAME': None,
  12. 'APPLICATION_ROOT': None,
  13. 'SESSION_COOKIE_NAME': 'session',
  14. 'SESSION_COOKIE_DOMAIN': None,
  15. 'SESSION_COOKIE_PATH': None,
  16. 'SESSION_COOKIE_HTTPONLY': True,
  17. 'SESSION_COOKIE_SECURE': False,
  18. 'SESSION_REFRESH_EACH_REQUEST': True,
  19. 'MAX_CONTENT_LENGTH': None,
  20. 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
  21. 'TRAP_BAD_REQUEST_ERRORS': False,
  22. 'TRAP_HTTP_EXCEPTIONS': False,
  23. 'EXPLAIN_TEMPLATE_LOADING': False,
  24. 'PREFERRED_URL_SCHEME': 'http',
  25. 'JSON_AS_ASCII': True,
  26. 'JSON_SORT_KEYS': True,
  27. 'JSONIFY_PRETTYPRINT_REGULAR': True,
  28. 'JSONIFY_MIMETYPE': 'application/json',
  29. 'TEMPLATES_AUTO_RELOAD': None,
  30. }

两种方式进行配置

1,通过对象属性赋值配置

  1. app.config['DEBUG'] = True
  2. #由于Config对象本质上是字典,所以还可以使用app.config.update(DEBUG=True)

2,通过py文件设置

  1. #通过py文件配置
  2. app.config.from_pyfile("python文件名称")
  3. 如:
  4. settings.py
  5. DEBUG = True
  6. app.config.from_pyfile("settings.py")
  7. #通过环境变量配置
  8. app.config.from_envvar("环境变量名称")
  9. #app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
  10. 环境变量的值为python文件名称名称,内部调用from_pyfile方法
  11. app.config.from_json("json文件名称")
  12. JSON文件名称,必须是json格式,因为内部会执行json.loads
  13. app.config.from_mapping({'DEBUG': True})
  14. 字典格式
  15. app.config.from_object("python类或类的路径")
  16. app.config.from_object('pro_flask.settings.TestingConfig')
  17. settings.py
  18. class Config(object):
  19. DEBUG = False
  20. TESTING = False
  21. DATABASE_URI = 'sqlite://:memory:'
  22. class ProductionConfig(Config):
  23. DATABASE_URI = 'mysql://user@localhost/foo'
  24. class DevelopmentConfig(Config):
  25. DEBUG = True
  26. class TestingConfig(Config):
  27. TESTING = True
  28. PS: sys.path中已经存在路径开始写
  29. PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_configTrue
  30. 则就是instance_path目录(Flask对象init方法的参数)

多url的路由

一个试图函数可以设置多个url路径去访问
一个url路径只可以又一个试图函数

装饰器与路由注解

视图装饰器应当放在最外层,否则里面的装饰器不会生效
视图函数包裹的装饰器不要return值,否则会被包装成返回对象,视图函数中的返回响应对象就不会生效了

  1. # 写个装饰器
  2. import time
  3. def log_time(func):
  4. def decorator(*args,**kwargs):
  5. print(F"{time.time()}")
  6. return func(*args,**kwargs)
  7. return decorator
  8. # 添加路由 视图函数
  9. @log_time # 放在这里的话装饰器不会被运行
  10. @app.route('/index') # hello,如果想要多个路径套用同一个视图的情况下,可以直接加注解叠加
  11. # 应当将扩展的装饰器放在这里
  12. def home(): # 多路径套用同一个视图 但是一个url不会对应多个视图函数
  13. # 1.接收参数
  14. # 2.调用对应的函数去处理数据
  15. # 3.构建响应结果
  16. return render_template('index.html')

路由参数化

主要有两种方式实现
1,直接从url中获取并传到视图函数中进行处理,并且可以对参数部分进行类型限制

  1. @app.route('/cases/<id>')
  2. def index(id):
  3. return F"{id}hello addicated"

2,第二种,通过request.args的get方法取到值,视图函数中将不再接收形参

  1. @app.route('/cases')
  2. def index1():
  3. id = request.args.get('id')
  4. return F"{id}hello addicated"

路由注册机制

两种方式进行注册

1,集中注册机制

  1. views.py
  2. def index():
  3. reutrn "这是集中注册机制去注册路由"
  4. app.add_url_rule('/index',view_func=views.index)

2,注解注册

  1. @app.route("/index")
  2. def index():
  3. return "这是装饰器注册路由"

app.url_map

flask中专门用来存放url路径与视图函数绑定关系的一个属性
可以体现出路径与视图函数的绑定关系
实例

  1. print(app.url_map)
  2. Map([<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
  3. 注册之前只有一个static/filename
  4. filename 可变参数,
  5. 路由: url 视图函数的绑定关系, static 是端点名称
  6. print(app.url_map)
  7. Map([<Rule '/hello' (HEAD, GET, OPTIONS) -> test>,
  8. test 是端点名称,如果不进行修改,默认为视图函数的名称
  9. # 端点名称可更改,在路由进行注册的时候可以通过属性赋值的方式进行更改
  10. # HEAD,GET,OPTIONS 是允许的请求方式,在路由注册时可以更改

app.rouet()可配置的参数

methods 限制路由的访问方式

  1. @app.route('/hello',methods=['POST'],endpoint='测试命名')
  2. # 注解方式注册路由配置methods
  3. app.add_url_rule('/hello', view_func=test,methods=['POST'])
  4. # 集中式注册机制中对methods设置

endpoint 端点命名

  1. @app.route('/hello',methods=['POST'],endpoint='测试命名')
  2. app.add_url_rule('/hello', view_func=test,
  3. methods=['POST'],endpoint="测试命名")

redirect_to

由编写方式不同成为两种状态
1,直接在 route参数内些重定向地址,配置地址,这种配置方法将直接跳过本视图函数的处理,直接返回给重定向的目标视图函数

  1. @app.route('/hello',methods=['POST'],endpoint='测试命名',redirect_to='/')

2,在视图函数返回值的时候书写,这种方式会在完成本视图的函数处理之后再进行重定向到目标页面

  1. @app.route('/cases')
  2. def index1():
  3. id = request.args.get('id')
  4. return redirect('/')

defaults

默认值设定,在设计路由参数化的案例中,有的时候需要给一个属性赋一个默认值,
同样根据路由注册方式不偶那个,有两种方式,效果一样
1,在route()参数中去设置,字典 kv对应形式

  1. @app.route('/hello',methods=['POST'],endpoint='测试命名',
  2. redirect_to='/',defaults={'id':3})

2,在视图函数中的形参上设置

  1. @app.route('/cases/<id>')
  2. def index(id=3): # 直接在形参处进行配置,简洁明了
  3. return F"{id}hello addicated"

Flask,大型项目作业时候注意的坑

视图函数的分离
背景:随着项目增大,吧视图函数单独放在一起,不将项目启动,注册路由,视图函数都放一个文件中,会出现分层的需要。所以项目结构会发生改变。
启动文件
视图函数
数据处理
views
其他的帮助函数

  1. views.py 视图层
  2. def index():
  3. return 'home'
  4. def case():
  5. return 'cases'
  6. urls.py 路由分发层
  7. from py_day23 import views
  8. from py_day23.py_day23_2 import app
  9. app.add_url_rule('/',view_func=views.index)
  10. app.add_url_rule('/case',view_func=views.case,methods=['POST'])
  11. run_app.py 启动层
  12. from flask import Flask, request
  13. app = Flask(__name__)
  14. if __name__ == '__main__':
  15. app.run(debug=True)

在这样分层的时候,很容出现的一个问题是,循环导入。因为平常的编写习惯,
很容将需要用到的包一股脑的全在项目文件头部进行一次性导入,这样当引用出现交叉时,
极易出现循环导入,而又难以去分析错误成因。
最好的方式是在编写大型项目的时候,用到什么就导入什么,不要偷懒一次性导入
并且在导入的时候不要导入模块,而是用到什么代码就导入模块下的代码,* 也是可以进行使用的