前言:
框架的对比
Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....);
Tornado:2大特性就是异步非阻塞、原生支持WebSocket协议;
Flask:封装功能不及Django完善,性能不及Tornado,但是Flask的第三方开源组件比丰富;http://flask.pocoo.org/extensions/
Bottle:比较简单;
总结:
不论优劣,不同的工具而已;
小型web应用设计的功能点不多使用Flask;
大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件);
如果追求性能可以考虑Tornado;
Flask的socket是基于Werkzeug 实现的,模板语言依赖jinja2模板,在使用Flask之前需要安装一下;
pip3 install flask #安装flask
Flask简单使用
from flask import Flask,response app=Flask(__name__) #创建1个Flask实例 @app.route('/') #路由系统生成 视图对应url, def first_flask(): #视图函数 return 'Hello World' #response if __name__ == '__main__': app.run() #启动socket
一、flask的配置文件
app=Flask(__name__,template_folder='templates',static_url_path='/static/',static_path='/lizhiqiang') #模板路径: template_folder='templates' #静态文件路径:static_url_path='/static/' #静态文件引入别名:static_path='/zhanggen' #设置为调试环境:app.debug=True (代码修改自动更新) #设置json编码格式 如果为False 就不使用ascii编码:app.config['JSON_AS_ASCII']=False #设置响应头信息Content-Type app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" (注意 ;charset=utf-8)
二、路由系统
1.动态路由(url传参)
@app.route('/user/<name>')
from flask import Flask app=Flask(__name__) @app.route('/<name>') #设置url传参数 http://127.0.0.1:5000/zhanggen def first_flask(name): #视图必须有对应接收参数 print(name) return 'Hello World' #response if __name__ == '__main__': app.run() 接收字符串类型参数
@app.route('/post/<int:age>')
#接收整型数字参数 app=Flask(__name__) @app.route('/<int:age>/') #设置url传参数 http://127.0.0.1:5000/18/ def first_flask(age): #视图必须有对应接收参数 print(age) return 'Hello World' #response if __name__ == '__main__': app.run() 接收整型数字参数
2、指定允许的请求方法
@app.route('/login', methods=['GET', 'POST'])
# 指定允许的请求方法 app=Flask(__name__) @app.route('/<path:url>/',methods=['get']) #只允许get请求 def first_flask(url): print(url) return 'Hello World' #response if __name__ == '__main__': app.run() 指定允许的请求方法
3、通过别名反向生成url
#反向生成url from flask import Flask,url_for app=Flask(__name__) @app.route('/<path:url>',endpoint='name1') def first_flask(url): print(url_for('name1',url=url)) #如果设置了url参数,url_for(别名,加参数) return 'Hello World' if __name__ == '__main__': app.run() url_for()反向生成url
4、扩展路由功能:正则匹配url
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from flask import Flask, views, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) class RegexConverter(BaseConverter): """ 自定义URL匹配正则表达式 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 :param value: :return: """ return int(value) def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 :param value: :return: """ val = super(RegexConverter, self).to_url(value) return val # 添加到flask中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("d+"):nid>') def index(nid): print(url_for('index', nid='888')) return 'Index' if __name__ == '__main__': app.run()
三、视图
1、给Flask视图函数加装饰器
注意如果要给视图函数加装饰器增加新功能,一点要加在路由装饰器下面,才会被路由装饰器装饰,才能生生成url关系;
#给Flask视图加装饰器 #1、定义1个装饰器 def auth(func): print('我在上面') def inner(*args,**kwargs): return func(*args,**kwargs) return inner app=Flask(__name__) @app.route('/',methods=['GET']) @auth #注意如果要给视图函数加装饰器,一点要加在路由装饰器下面,才会被路由装饰器装饰 def first_flask(): print('ffff') return 'Hello World' if __name__ == '__main__': app.run()
#给Flask视图加装饰器 #1、定义1个装饰器 def auth(func): print('我在上面') def inner(*args,**kwargs): return func(*args,**kwargs) return inner app=Flask(__name__) @app.route('/',methods=['GET']) @auth #注意如果要给视图函数加装饰器,一点要加在路由装饰器下面,才会被路由装饰器装饰 def first_flask(): print('ffff') return 'Hello World' if __name__ == '__main__': app.run()
2、request和response
a.请求相关信息
request.method: 获取请求方法
request.json
request.json.get("json_key"):获取json数据 **较常用
request.argsget('name') :获取get请求参数
request.form.get('name') :获取POST请求参数
request.form.getlist('name_list'):获取POST请求参数列表(多个)
request.values.get('age') :获取GET和POST请求携带的所有参数(GET/POST通用)
request.cookies.get('name'):获取cookies信息
request.headers.get('Host'):获取请求头相关信息
request.path:获取用户访问的url地址,例如(/,/login/,/ index/);
request.full_path:获取用户访问的完整url地址+参数 例如(/login/?age=18)
request.script_root: 抱歉,暂未理解其含义;
request.url:获取访问url地址,例如http://127.0.0.1:5000/?age=18;
request.base_url:获取访问url地址,例如 http://127.0.0.1:5000/;
request.url_root
request.host_url
request.host:获取主机地址
request.files:获取用户上传的文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename)) 直接保存
b、响应相关信息
return "字符串" :响应字符串
return render_template('html模板路径',**{}):响应模板
return redirect('/index.html'):跳转页面
3 、Flask之CBV视图
#CBV视图 from flask import Flask,url_for,views #----------------------------------------------------- app=Flask(__name__) #装饰器 def auth(func): print('我在上面') def inner(*args,**kwargs): return func(*args,**kwargs) return inner #-------------------------------------------------------- class IndexView(views.MethodView): #CBV视图 methods=['GET'] #允许的http请求方法(改CBV只允许GET方法) decorators = [auth,] #每次请求过来都加auth装饰器 def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index/',view_func=IndexView.as_view(name='name1')) #(name='name1'反向生成url别名 if __name__ == '__main__': app.run()
五、模板语言
Flask使用的是Jinja2模板,所以其语法和Django无差别(Django的模板语言参考Jinja2)
1.引用静态文件
方式1:别名引入
<link rel="stylesheet" href="/zhanggen/commons.css">
方式2:url_for()方法引入
<link rel="stylesheet" href="{{ url_for('static',filename='commons.css') }}">
2.模板语言引用上下文对象
变量
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<h1>{{user_list}}</h1> <!--变量 -->
<h1>{{user_list}}</h1> <!--变量 -->
循环、索引取值
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<ul>
{% for user in user_list %} <!--循环 -->
<li>{{user}}</li>
{% endfor %}
{{user_list.0}} <!-- 索引取值-->
</ul>
<ul> {% for user in user_list %} <!--循环 --> <li>{{user}}</li> {% endfor %} {{user_list.0}} <!-- 索引取值--> </ul>
Flask的Jinjia2可以通过Context 把视图中的函数传递把模板语言中执行,这就是Django中的simple_tag和simple_fifter;
simple_tag(只能传2个参数,支持for、if)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
@app.template_global() #simple_tag def foo(arg): return '<input type="text">'
@app.template_global() #simple_tag def foo(arg): return '<input type="text">'
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<h1>{{foo(1)|safe}}</h1> <!--Flask的模板语言支持simple_tag-->
<h1>{{foo(1)|safe}}</h1> <!--Flask的模板语言支持simple_tag-->
3.wtform(flask表单验证插件)
3.1. 安装
pip install wtforms #安装wtfroms插件
3.2登录注册
from flask import Flask,render_template,request from wtforms import Form from wtforms.fields import simple,core from wtforms import validators app = Flask(__name__) #登录 class LoginFrom(Form): username = simple.StringField( label='用户名', validators=[ validators.DataRequired(message='用户名不能是空'), validators.Length(min=3,max=16,message='用户名必须大于%(min)d且小于%(max)d') ], ) password = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能是空'), validators.Length(min=3, max=16, message='密码必须大于%(min)d且小于%(max)d') ], ) @app.route('/',methods=['GET','POST']) def login(): if request.method == 'GET': fm = LoginFrom() return render_template('login.html',wtf=fm) else: form = LoginFrom(formdata=request.form) if form.validate(): return "ok" else: return render_template('login.html',wtf=form) #注册 class RegForm(Form): username=simple.StringField( label='用户名', validators=[ validators.DataRequired(message='用户名不能为空'), validators.Length(min=3,max=16,message='用户名必须大于%(min)d且小于%(max)d'), ] ) password = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能是空'), validators.Length(min=3, max=16, message='密码必须大于%(min)d且小于%(max)d'), validators.Email(message='密码必须符合邮箱规则') ], ) repassword= simple.PasswordField( label='确认密码', validators=[validators.EqualTo(fieldname='password',message='密码不一致')] ) gender=core.SelectMultipleField( label="爱好", validators=[validators.Length(min=2, max=4, message="癖好有问题")], coerce=int, choices=( (1, "fengjie"), (2, "luoyufeng"), (3, "lixueqin"), (4, "wuyifan"), (5, "panta") ), default=(1, 3, 5) ) @app.route('/reg',methods=["GET","POST"]) def reg(): if request.method == "GET": fm = LoginFrom() return render_template("reg.html",rf=fm) else: form = LoginFrom(request.data) if form.validate(): return form.data.get("password") else: return render_template("reg.html", rf=form) if __name__ == '__main__': app.run(debug=True)
html
#login.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post" novalidate> {{ wtf.username.label }} {{ wtf.username }} <p><h1>{{wtf.username.errors.0}}</h1></p> <p> {{ wtf.password.label }} {{ wtf.password }} </p> <p><h1>{{wtf.password.errors.0}}</h1></p> <input type="submit" value="登录"> </form> </body> </html> #reg.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post" novalidate> {% for field in rf %} <p>{{ field.label }}{{ field }}{{ field.errors.0 }}</p> {% endfor %} <input type="submit" value="注册"> </form> </body> </html>
3.33.2.wtforms源码 猜想....
源码给你们一个链接吧,头疼
https://www.cnblogs.com/sss4/p/8097653.html
未完待续。。。