目录
一、web框架:
最核心的事情
编辑安装
二、创建flask项目
1.最小原型
2.flask断点调试之URL传参
3.URL路由映射
4. POSTMAN 收发数据
POST
5.响应
1)定义响应格式
json
html
TXT
2)定义响应码
3)定义响应头参数
三、app()源码解析
四、模板渲染
1.前后端分离与不分离
2.模板渲染示例
render_template()函数解析
3.如何传递数据
准备一组数据
定义路由,传入数据变量
使用变量p及逻辑代码编写html
编辑
渲染效果
4.过滤器
特性
字符串过滤
数字过滤
列表过滤
json过滤
自定义过滤
参考文档
5.测试test
6.全局函数global
特性
7.继承extend
特性
父类(基模板)
子模版
include
宏
一、web框架:
最核心的事情
请求分派
制造响应
安装
直接安装 pip install flask
虚拟安装 python -m venv venv
请求分派
制造响应
直接安装 pip install flask
虚拟安装 python -m venv venv
二、创建flask项目
1.最小原型
from wsgiref.simple_server import make_server
def app(env,response):
# "flask/django application"
print("正在监听")
response('200 OK',[("content-type",'text/html')]) #定义响应头
return ['cuteboy']
# 初始化一个服务器
server = make_server('',5100,app)
server.serve_forever(0.2)
2.flask断点调试之URL传参
1)在地址栏运行 http://localhost:5100/login/?usr=lyr
2)在print()语句添加断点,点击小虫子调试按钮:
3)刷新浏览器界面
4)进入pycharm调试器界面,点开env环境变量列表,观察如下关键变量
3.URL路由映射
from flask import Flask
app = Flask(__name__)#得到APP对象
#路由
@app.route('/login/')
def index():
"""视图函数"""
return "login ok"
@app.route('/projects/')
def projects():
"""视图函数"""
return "projects ok"
app.run()#启动web服务,也可以用uwsgi,flask自带的测试服务器
127.0.0.1:5000/projects/
# def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
:param host:要侦听的主机名。将其设置为`0.0.0.0``to
让服务器在外部也可用。默认为“127.0.0.1”或“SERVERu NAME”配置变量中的主机
:param port:Web服务器的端口。默认为“5000”或在“SERVERu NAME”配置变量中定义的端口
:param debug:如果给定,则启用或禁用调试模式。看见
:attr:'debug'。
:param loadu dotenv:加载最近的:文件:`。env`和:文件:`。弗拉斯肯夫`
用于设置环境变量的文件。也会改变工作方式
目录到包含找到的第一个文件的目录。
:param options:转发到底层Werkzeug的选项
服务器见:func:` werkzeug。服务run_simple`了解更多信息
信息
4. POSTMAN 收发数据
POST
from flask import Flask,request
app = Flask(__name__)#得到APP对象
#路由
@app.route('/',methods=['POST'])
def hello():
"""视图函数"""
#获取请求当中的post
bodydata = request.form
print (bodydata)
return "hello world"
(base) PS D:TELEARNINGKDTLearningwebflask快速开始> flask run
from flask import Flask,request
app = Flask(__name__)#得到APP对象
#路由
@app.route('/',methods=['POST'])
def hello():
"""视图函数"""
#获取请求当中的post
bodydata = request.form
print (bodydata)
return "hello world"
(base) PS D:TELEARNINGKDTLearningwebflask快速开始> flask run
D:TELEARNINGKDTLearningwebflask快速开始app.py:38: Warning: Silently ignoring app.run() because the application is run from the flask command line ex
ecutable. Consider putting app.run() behind an if __name__ == "__main__" guard to silence this warning.
app.run(debug=True)
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [20/Jul/2022 00:52:49] "?[31m?[1mGET / HTTP/1.1?[0m" 405 -
ImmutableMultiDict([('"username', 'lyr')])
127.0.0.1 - - [20/Jul/2022 00:53:05] "?[37mPOST / HTTP/1.1?[0m" 200 -
5.响应
1)定义响应格式
-
json
-
html
-
TXT
2)定义响应码
-
json
-
html
-
TXT
2)定义响应码
3)定义响应头参数
三、app()源码解析
四、模板渲染
1.前后端分离与不分离
2.模板渲染示例
-
render_template()函数解析
def render_template(template_name_or_list, **context):
#**context是上下文
"""Renders a template from the template folder with the given
context.
:param template_name_or_list: the name of the template to be
rendered, or an iterable with template names
the first one existing will be rendered
:param context: the variables that should be available in the
context of the template.
"""
ctx = _app_ctx_stack.top
ctx.app.update_template_context(context)
return _render(
ctx.app.jinja_env.get_or_select_template(template_name_or_list),
context,
ctx.app,
)
3.如何传递数据
-
准备一组数据
#测试数据
projects_data =[
{"name": "CUPID","tester": "luoyiran","createtime":2022.01},
{"name": "DDH", "tester": "yangshuokai", "createtime": 2022.02},
{"name": "Pair", "tester": "liuwenxing", "createtime": 2022.03},
{"name": "Pevic", "tester": "liran", "createtime": 2022.04},
{"name": "AutoEF", "tester": "gaorui", "createtime": 2022.05},
{"name": "3Dbaby", "tester": "yuhao", "createtime": 2022.06},
]
-
定义路由,传入数据变量
@app.route('/test3/')
def test3():
"""如何传递数据"""
return render_template('test3.html',p=projects_data)
-
使用变量p及逻辑代码编写html
展示测试状态信息
获取全局变量config
{{ config }}
打印全局变量config的键值
MAX_COOKIE_SIZE: {{ config ['MAX_COOKIE_SIZE'] }}
获取全局变量request
{{ request }}
展示测试状态信息
{% for project in p%}
{%set name = project['name']%}
{%set tester = project['tester']%}
{%set createtime = project['createtime']%}
{% if tester=="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime}}
{% elif tester!="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime}}
{% endif %}
{% endfor %}
-
渲染效果
准备一组数据
定义路由,传入数据变量
使用变量p及逻辑代码编写html
展示测试状态信息
获取全局变量config
{{ config }}
打印全局变量config的键值
MAX_COOKIE_SIZE: {{ config ['MAX_COOKIE_SIZE'] }}
获取全局变量request
{{ request }}
展示测试状态信息
{% for project in p%}
{%set name = project['name']%}
{%set tester = project['tester']%}
{%set createtime = project['createtime']%}
{% if tester=="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime}}
{% elif tester!="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime}}
{% endif %}
{% endfor %}
-
渲染效果
4.过滤器filter
特性
| [过滤器名字]
字符串过滤
数字过滤
列表过滤
json过滤
自定义过滤
@app.template_filter("dt_to_string")
def dt_to_string(dt):
return dt.strftime("%Y-%m-%d")
展示测试状态信息
首页 联系我们
获取全局变量config
{{ config }}
打印全局变量config的键值
MAX_COOKIE_SIZE: {{ config ['MAX_COOKIE_SIZE'] }}
获取全局变量request
{{ request }}
展示测试状态信息
{% for project in p%}
{%set name = project['name']%}
{%set tester = project['tester']%}
{%set createtime = project['createtime']%}
{% if tester=="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime |dt_to_string }}
{% elif tester!="luoyiran" %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime|dt_to_string}}
{% endif %}
{% endfor %}
测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime |dt_to_string }}
{% elif tester!="luoyiran" %} 测试项目:{{name}} 测试人员:{{tester}} 创建时间:{{createtime|dt_to_string}}{% endif %} {% endfor %}
过滤效果:
参考文档
jinjia2(内置过滤器清单)
5.测试器 test
6.全局函数 global
特性
7.继承extend
特性
7.继承extend 特性
如随意跳转,网易顶部导航页/页脚一般不会变 “ 首页 | 联系我们”
父类(基模板)
所有子页面继承这个页面(basepage),可以理解为组件
子模版
include
宏
python flask路由post无法解析:A request was sent to thishttps://zhuanlan.zhihu.com/p/107383595
五、FLASK路由原理和可插拔视图 特性我们的声明:
@app.route('/', methods=['get', 'post'])例如:post请求 http://127.0.0.1:5000/ 访问没问题。
post请求 http://127.0.0.1:5000 解析出错
正确的声明方法是:
@app.route('/', methods=['get', 'post'], strict_slashes=False)
这样不会再 严格的要求 斜杠post请求 http://127.0.0.1:5000 访问正确
wsgi程序如何处理路由 自制路由装饰器@route()1.添加路由的方式很简单
2.路由就是把URL和需要执行的程序绑定在一起
3.输入URL,调用对应的函数
# 路由地图
url_map = {}
# 添加路由函数
def add_url_rule(url,view_func):
"""添加路由"""
url_map[url] = view_func
app.add_url_rule('/login',view_func = login)
app.add_url_rule('/',view_func = index)
def route(url):
# 路由装饰器
def decorator(f):
add_url_rule(url, f)
return f
return decorator
@route('/case')
def case():
return "case ok"
print("url.map:",url_map) #map是对象
def app(env,response):
url = env.get('PATH_INFO') # 接口地址
# para = env.get('QUERY_STRING')
print("url:",url)
# print("para:",para)
if url is None or (url not in url_map.keys() ):
response('404 ok',[('content-type','text/plain'),])
res = "页面不存在"
return [res.encode()]
else:
response('200 ok', [('content-type', 'text/plain'), ])
res = url_map.get(url)
print (res)
return [res().encode()]
自定义时间打印装饰器
# 路由函数的装饰器必须放在route装饰器下
def printtime(f):
"""打印时间"""
def decorator():
print (datetime.datetime.now())
return "time ok"
return decorator
@route('/case')
@printtime
# 路由函数的装饰器必须放在route装饰器下
def case():
return "case ok"
URL和视图函数的数量关系
# 问题1 一个URL=====》route装饰器将同个url赋值给多个视图函数,可行? # 问题2 一个视图函数====>赋值给多个URL,可行?
# 添加路由规则,关联url和视图函数
def add_url_rule(url,view_func):
"""添加路由
key:url
value:视图函数
# 使用此种方法:字典里的key不能重复,后绑定的视图函数会覆盖前面绑定了同个路由的视图函数返回结果
url_map[url] = view_func
# 使用此种方法:字典里的key不能重复,后面绑定同个key(url)的视图函数时,会先判断前面是否绑定相同key,若绑定,无法写入字典
# url_map.setdefault(url,view_func)
"""
# url_map[url] = view_func
url_map.setdefault(url,view_func)
@route('/case')
def case():
return "case ok"
@route('/case')
def case2():
"""问题1"""
return "case2 ok"
五、类视图 1.类视图有什么好处?url_map[url] = view_func 返回结果:调用了case2()
url_map.setdefault(url,view_func) 返回结果:调用了case()
2.类视图demo View1)类是可以继承的
2)代码可以复用
3)可以定义多种行为 类:方法/行为/属性/特征
4)类:不同的请求方式 get/post/delete
特性 | View类衍生出来的现成写法
1.在app.py编写如下代码
from flask import Flask, request
from flask import render_template,redirect
from flask.views import View
from wsgiref.simple_server import make_server
app = Flask(__name__,
template_folder ='pages',
static_folder ='static'
) # 得到APP对象
# 修改配置
app.config['JSON_AS_ASCII'] = False # 返回字符设置
# 测试数据
projects_data = [
{"name": "CUPID", "tester": "luoyiran"},
{"name": "DDH", "tester": "yangshuokai"},
]
# 类视图
class ProjectView(View):
# View视图一定要记得定义methods
methods = ['GET', 'POST', 'PUT']
def get(self):
return "get ok",200
def post(self):
return "post ok",211
def dispatch_request(self):
"""一定要实现,这是一个规范,第二次请求的分派
"""
#获取请求方法,根据请求方法,调用不同的实例方法
method = request.method.lower()
if method == 'get' :
return self.get()
elif method == 'post':
return self.post()
else:
return "Method not allowed",405
# 注册视图
# 基于类的视图,不要用装饰器,采取集中注册的形式,add_url_rule
# view_func 是一个类 ,需要添加as_view("XXX")
app.add_url_rule('/project1',view_func = ProjectView.as_view('PV'))
if __name__ == '__main__':
app.run(debug=True)
2.打开postman,访问路由视图'/project1’
1)发送post请求
2)发送get请求
3)发送其他请求
MethodView特性 | 是flask针对现在的RESTful风格的接口设计出来的
1.在app.py编写如下代码
from flask import Flask, request
from flask import render_template,redirect
from flask.views import View,MethodView
from wsgiref.simple_server import make_server
# get : 获取资源
# post :创建资源
# put :更新资源
# delete :删除资源
app = Flask(__name__,
template_folder ='pages',
static_folder ='static'
) # 得到APP对象
# 修改配置
app.config['JSON_AS_ASCII'] = False # 返回字符设置
# 类视图
class ProjectView(MethodView):
def get(self):
return "MethodView get ok",200
def post(self):
return "MethodView post ok",211
# 注册视图
# 基于类的视图,不要用装饰器,采取集中注册的形式,add_url_rule
# view_func 是一个类 ,需要添加as_view("XXX")
app.add_url_rule('/project1',view_func = ProjectView.as_view('PV'))
if __name__ == '__main__':
app.run(debug=True)
2.postman测试
3.实现指定的methods类属性,照样可以控制请求方法
就算类当中实现了实例方法get(),post(),put()等等,也是不支持对应的请求方法的
class ProjectView(MethodView):
# 实现指定的methods类属性,照样可以控制请求的方法
methods = ['GET'] #相当于:禁用ProjectView类试图里的除了get()以外的所有请求函数
def get(self):
return "MethodView get ok",200
def post(self):
return "MethodView post ok",211
postman测试
类视图为何能够生效?【原因】因为类实现了as_view( )这个方法
- 视图函数 : /project ==> def project()
- 类视图: /project ==> def view( ) ==> 调用dispatch_request( )
view.py
class View(object):
"""使用视图函数的替代方法。一个子类必须实现:meth:`dispatch_request`,
它使用来自 URL 路由系统的视图参数调用。
如果提供了 :attr:`methods`,
则方法不必显式传递给 :meth:`~flask.Flask.add_url_rule` 方法
class MyView(View):
methods = ['GET']
def dispatch_request(self, name):
return 'Hello %s!' % name
app.add_url_rule('/hello/', view_func=MyView.as_view('myview'))
# 当你想装饰一个可插入的视图时,你必须在创建视图函数时这样做:
# 通过包装:meth:`as_view`的返回值,或者你可以使用:attr:`decorators`属性::
class SecretView(View):
methods = ['GET']
decorators = [superuser_required]
def dispatch_request(self):
...
# 储在装饰器列表中的装饰器在创建视图函数时一个接一个地应用。请注意,您不能使用基于类
# 的装饰器,因为它们会装饰视图类而不是生成的视图函数
"""
#此视图可以处理的方法列表
methods = None
# 设置此项禁用或强制启用自动选项处理
provide_automatic_options = None
"""
# 装饰基于类的视图的规范方法是装饰 as_view() 的 : 返回值。
# 然而,由于这将部分 : 逻辑从类声明移动到它被钩住的地方 : 进入路由系统。
# 你可以在这个列表中放置一个或多个装饰器,每当创建视图函数时,结果就会自动被装饰。
# 0.8
"""
decorators = ()
def dispatch_request(self):
"""
子类必须重写此方法才能实现 实际查看功能代码。这个方法被全部调用 URL 规则中的参数。
"""
raise NotImplementedError()
@classmethod
def as_view(cls, name, *class_args, **class_kwargs):
"""将类转换为可以使用的实际视图函数 与路由系统。在内部,这会在 fly
它将在每个请求上实例化 View 并调用 :meth:`dispatch_request` 方法。
传递给 as_view 的参数被转发到类的构造函数。
"""
def view(*args, **kwargs):
self = view.view_class(*class_args, **class_kwargs)
return self.dispatch_request(*args, **kwargs)
if cls.decorators:
view.__name__ = name
view.__module__ = cls.__module__
for decorator in cls.decorators:
view = decorator(view)
"""
# 我们将视图类附加到视图函数有两个原因:首先,它可以让我们轻松找出这个东西
# 来自哪个基于类的视图,其次,它还用于实例化视图类,因此您实际上可以用某些
# 东西替换它否则用于测试目的和调试。
"""
view.view_class = cls
view.__name__ = name
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.methods = cls.methods
view.provide_automatic_options = cls.provide_automatic_options
return view



