flask框架基础分析
web框架原理
| 1.bs 架构 |
| bs架构其实就是我们利用socket写的一个服务端 |
| 符合wsgi协议 |
| WSGI:web Server Gateway Interface ,WSGI不是服务器,也不是python模块,框架,API或者任何软件,他只是一种规范,描述web server如何与web application通信的规范。 是web服务器和web应用程序之间或框架之间的通用接口标准,WSGI就像一座桥梁,WSGI的接口分为两个:一个是web服务器的接口,另一个是与服务器端程序的接口,WSGI的作用就是在协议之间进行转化,WSGI将web组件分成了三类:web服务器(WSGI Server)、Web中间件(WSGI Middleware) 与Web应用程序(WSGI Application) |
| Web Serber接收HTTP请求,封装一系列环境变量,按照WSGI接口标砖调用注册的WSGI application(如:django程序),最后响应返回给客户端。 |
| 虽然WSGI的设计目标是连接标砖的Web服务器(Nginx、Apache)与服务器端程序,但它本身也可以作为web服务器运行。但由于性能方面的限制,该服务器一般只是在测试的时候使用。 |
| |
| 2. 使用wsgiref协议 |
| wsgiref则是官方给出的一个实现了WSGI标准用于演示的简单python内置库,它实现了一个简单的WSGI Server和WSGI Application(在simple_server模块中),主要分为五个模块:simple_server,util,headers,handlers,validate.本质上就是编写一个socket服务端,用于接受用户请求(django) |
| |
| 3.使用werkzeug协议 |
| werkzeug不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个WSGI工具包,他可以作为一个Web框架的底层库,因为它封装好了很多Web框架的东西,werkzeug本质上就是编写一个socket服务端,勇于接受用户请求(flask)和django中wsgiref是类似的。 |
| |
| 4.uwsgi |
| uwsgi是一种线路协议,是uwsgi服务器独占的协议,用于定义传输信息类型(type of information),每一个 uwsgi packet 前4byte为信息传输类型的描述,与WSGI协议是两种东西。 |
| uwsgi是一个web服务器,它实现了WSGI协议。uwsgi、http等协议。Nginx中Httpuwsgimodule的作用是与uwsgi服务器进行交换。django项目部署实际上是uwsgi,他才是web服务器,而不是wsgi。 |
配置文件写法
| 项目的配置文件:如果不配,有默认的 |
| 几个重要的 |
| DEBUG:是否是调试模式 |
| SECRET_KEY:项目的秘钥 |
| print(app.config) |
| 1 使用配置文件之一:(写小脚本测试阶段用)直接通过app对象,配置上,只能配置几个,本质都要放到app.config中 |
| app.debug=True |
| app.secret_key='asdfasf4555' |
| app.session_cookie_name='sss' |
| print(app.config) |
| |
| 2 直接通过app.config 配置 |
| app.config['DEBUG'] = True |
| app.config['SECRET_KEY'] = 'asfasdf' |
| print(app.config) |
| |
| 3 通过配置文件(很像djagno),不常用 |
| app.config.from_pyfile('settings.py') |
| print(app.config) |
| |
| 4 通过类配置(用的多,可以有多套配置) |
| app.config.from_object('setting.DevelopmentConfig') |
| app.config.from_object('setting.ProductionConfig') |
| print(app.config) |
| |
| 5 以下,做了解 |
| app.config.from_envvar("环境变量名称") |
| app.config.from_json("json文件名称") |
| |
| 使用分布式配置中心 |
| import requests |
| res=requests.get('asdfasdfasdf').json() |
| app.config.from_mapping(res) |
| 拓展:配置文件都在本地 |
路由系统
| flask 的路由系统,djagno中,路由是单独的urls.py,flask中是装饰的形式 |
| |
| 1.使用方式 |
| @app.route:重要的参数 |
| -rule: 字符串的路径,使用转换器 <string:name> <name> |
| 'default': UnicodeConverter, |
| 'string': UnicodeConverter, |
| 'any': AnyConverter, |
| 'path': PathConverter, |
| 'int': IntegerConverter, |
| 'float': FloatConverter, |
| 'uuid': UUIDConverter, |
| 2.记住:string,int,path |
| -methods: 列表,规定请求的方式,如果列表中没有,该请求方式不被支持 |
| -endpoint:路由别名,如果不写,会以被装饰的函数名作为别名,django中叫name |
路由的本质
| 1.flask中路由是使用装饰器的,但是它的本质其实是app对象(Flask)的方法self.add_url_rule(rule, endpoint, f, **options) |
| |
| 2.如果在视图函数上加了装饰器,其实本质是在调用self.add_url_rule,我们可以不加装饰器,自己调用这个方法,也能完成路由的注册 |
| |
| 3.路由本质: |
| 1. @app.route('/') 先执行完成,结果是decorator内层函数 |
| @decorator |
| def index(): |
| 2. index=decorator(index) |
| def decorator(f): |
| |
| endpoint = options.pop("endpoint", None) |
| |
| self.add_url_rule(rule, endpoint, f, **options) |
| return f |
| 3 加了装饰器最终,返回的还是index,只不过执行了 self.add_url_rule(rule, endpoint, f, **options) |
| |
| 4 Flask类中得add_url_rule方法 |
| -rule:就是装饰器传入的路径,路由 |
| -endpoint:别名 |
| -view_func:视图函数不加括号 |
| |
| 5 得到的结论,现在不需要使用装饰器来注册路由了,自己写 |
| |
| app.add_url_rule('/home', view_func=home, endpoint='home') |
| |
| |
| 4.其实跟djagno没有大的差距,只是使用装饰器来配置 |
| @app.route和app.add_url_rule参数: |
| rule, URL规则 |
| view_func, 视图函数名称 |
| defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'} |
| 为函数提供参数,就是djagno中得kwargs |
| |
| endpoint = None, 名称,用于反向生成URL,即: url_for('名称'),等同于django的reverse |
| methods = None, 允许的请求方式,如:["GET", "POST"] |
| |
| strict_slashes 对URL最后的 / 符号是否严格要求 |
| strict_slashes = None |
| @app.route('/index', strict_slashes=False) |
| |
| @app.route('/index', strict_slashes=True) |
| |
| redirect_to 重定向到指定地址 |
| redirect_to = None, |
| @app.route('/index/<int:nid>', redirect_to='/home/<nid>') |
flask cbv写法
| 第一步:写一个类,继承MethodView |
| class Login(MethodView): |
| def get(self): |
| return '我是get' |
| def post(self): |
| return '我是psot' |
| |
| 第二步:注册路由 name 是别名,本质就是endpoint |
| app.add_url_rule('/login', view_func=Login.as_view(name='index')) |
| |
| 第三步:只要向 /login 发送get请求,就会执行Login 的get方法 |
| 1.研究第0个问题:cbv加装饰器,如何做? |
| 类属性中加入,加入decorators = [auth, ],属性是一个列表,按照列表顺序,依次给每个方法加装饰器 |
| |
| def as_view(cls, name, *class_args, **class_kwargs ) : |
| .... |
| if cls.decorators: |
| for decorator in cls.decorators: |
| ''' |
| # 装饰器原理: |
| @auth |
| def view(): |
| 本质是 view=auth(view) |
| ''' |
| |
| view = decorator(view) |
| return view |
| 1.研究第1个问题,as_view的执行流程 |
| def as_view(cls, name, *class_args, **class_kwargs): |
| def view(**kwargs): |
| return self.dispatch_request(**kwargs) |
| return view |
| |
| -请求来了,路由匹配成功,会执行as_view内的view()----》self.dispatch_request---》MethodView的dispatch_request |
| -MethodView的dispatch_request |
| def dispatch_request(self, **kwargs): |
| 在当前视图类中反射,请求方式的小写字符串(get),我们写了get方法 |
| meth = getattr(self, request.method.lower(), None) |
| 执行get() |
| return meth(**kwargs) |
| |
- 在as_view(name='xxx')中name的作用
| 1.研究第2个问题:Login.as_view(name='index') name到底有什么用,还必须传 |
| -先研究 endpoint 有什么用,正常的fbv,如果不写endpoint,会以函数名作为别名,endpoint如何设置的 |
| -如果endpoint为None,它把函数名作为了endpoint |
| if endpoint is None: |
| endpoint = _endpoint_from_view_func(view_func) |
| options["endpoint"] = endpoint |
| |
| -Login.as_view(name='index'),name到底有啥用 |
| -app.add_url_rule('/login', view_func=Login.as_view('login')) |
| -没有传endpoint,Login.as_view('login')是 view函数的内存地址, |
| -endpoint会以函数名作为endpoint的值,现在所有函数都是view,必须传入name,来修改调view函数的名字 |
| -如果传了endpoint,别名以endpoint为主,如果不传endpoint,别名以name为主 |
| app.add_url_rule('/login', view_func=Login.as_view(name='login'),endpoint='xxx') |
| |
| -用来控制允许的请求方式 |
| -如果不写,写了什么方法,就允许什么请求 |
flask 模板语法
| 1.在我们之前学习的dtl中的所有语法,flask语法都基本支持,并且能够使用,函数的方式进行传参 |
| |
| 2.view页面 |
| from flask import Flask, render_template,Markup |
| app = Flask(__name__) |
| @app.route('/') |
| def index(): |
| |
| return render_template('test.html', |
| user={ |
| 1: {'name': 'joseph', 'age': 19, 'hobby': '篮球'}, |
| 2: {'name': 'sylvia', 'age': 20, 'hobby': '橄榄球'}, |
| 3: {'name': 'judy', 'age': 21, 'hobby': '乒乓球'}, |
| }) |
| |
| a='<a href="http://www.baidu.com">点我看黑丝</a>' |
| |
| return render_template('test.html',a=a) |
| if __name__ == '__main__': |
| app.run() |
HTML页面
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>Title</title> |
| </head> |
| <body> |
| { |
| |
| |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| |
| |
| { |
| { |
| { |
| { |
| { |
| { |
| { |
| |
| |
| { |
| {{ a}} |
| |
| |
| </body> |
| </html> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)