Python Web开发之Flask - Go语言中文社区

Python Web开发之Flask


Python Web开发之Flask

前言:

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
from werkzeug.wrappers import Request, Response # Flask的socket使用werkzeug实现,所以要导入 werkzeug@Request.application
def hellow(request):return Response('Hello World')
if__name__ == '__main__':from werkzeug.serving import run_simple run_simple('localhost',400,hellow)
werkzeug

 

Flask简单使用

from flask import Flask
app=Flask(__name__) #创建1个Flask实例@app.route('/') #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask)def first_flask(): #视图函数return'Hello World'#response
if__name__ == '__main__': app.run() #启动socket
View Code

 

 

一、配置文件

 

app=Flask(__name__,template_folder='templates',static_url_path='/static/',static_path='/zhanggen')

模板路径: 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/zhanggendef 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()
接收整型数字参数

@app.route('/post/<float:salary>')

#接收浮点型型数字参数app=Flask(__name__)@app.route('/<float:salary>/') #设置url传参数http://127.0.0.1:5000/2345555.8889/def first_flask(salary): #视图必须有对应接收参数print(salary)return'Hello World'#response
if__name__ == '__main__': app.run()
接收浮点型数字参数

@app.route('/post/<path:path>')

# 接收URL链接类型参数app=Flask(__name__)@app.route('/<path:url>/') #设置url传参数:http://127.0.0.1:5000/http://www.baiu.com/def first_flask(url): #视图必须有对应接收参数print(url)return'Hello World'#response
if__name__ == '__main__': app.run()
接收URL链接类型参数

 

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

#反向生成urlfrom flask import Flask,url_forapp=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、通过app.add_url_rule()调用路由

#方式2通过app.add_url_rule()方法的方式调用路由app=Flask(__name__)
def first_flask():return'Hello World'
app.add_url_rule(rule='/index/',endpoint='name1',view_func=first_flask,methods=['GET'])#app.add_url_rule(rule=访问的url,endpoint=路由别名,view_func=视图名称,methods=[允许访问的方法])if__name__ == '__main__': app.run()
app.add_url_rule()方法调用路由

 

5、扩展路由功能:正则匹配url

如果需要一些复杂的匹配规则可以自定义正则匹配url

from flask import Flask, views, url_forfrom 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()
View Code

 

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'):跳转页面

 

响应json数据

方式1: return jsonify(user_list) 

app.config['JSON_AS_ASCII']=False #指定json编码格式 如果为False 就不使用ascii编码,app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8"#指定浏览器渲染的文件类型,和解码格式;
配置

方式2:

return Response(data,mimetype="application/json;charset=utf-8",)

 

 

如果需要设置响应头就需要借助make_response()方法

 

from flask import Flask,request,make_response 

 

response = make_response(render_template('index.html'))

response是flask.wrappers.Response类型

response.delete_cookie('key')

response.set_cookie('key', 'value')

response.headers['X-Something'] = 'A value'

return respons

 

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()
CBV视图

 

 

五、模板语言

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.模板语言引用上下文对象

变量

<h1>{{user_list}}</h1> <!--变量 -->
View Code

 

循环、索引取值

<ul>{% for user in user_list %} <!--循环 --> <li>{{user}}</li>{% endfor %}
{{user_list.0}} <!-- 索引取值-->
</ul>
View Code

 

Flask的Jinjia2可以通过Context 把视图中的函数传递把模板语言中执行,这就是Django中的simple_tag和simple_fifter;

simple_tag(只能传2个参数,支持for、if)

@app.template_global() #simple_tagdef foo(arg):return'<input type="text">'
视图
<h1>{{foo(1)|safe}}</h1><!--Flask的模板语言支持simple_tag-->
模板语言

 

simple_fifter(对参数个数无限制,不支持for、if)

@app.template_filter() #simple_fifterdef foo1(arg1,arg2,arg3):return arg1+arg2+arg3
视图
<h1> {{ 'alex'|foo1('s ','b',) }} </h1><!-- simple_fifter -->
模板语言

 

3.wtform(flask表单验证插件)

3.0.简介

 wtformWTForms是一个支持多个web框架的form组件,主要对用户请求数据 进行表单验证

 

3.1. 安装

pip install wtforms #安装wtfroms插件

 

3.2.简单使用

wtforms和Django自带的form验证插件功能相同,使用起来大同小异;

 

用户登录页面验证

#!/usr/bin/env python# -*- coding:utf-8 -*-from flask import Flask, render_template, request, redirectfrom wtforms import Formfrom wtforms.fields import corefrom wtforms.fields import html5from wtforms.fields import simplefrom wtforms import validatorsfrom wtforms import widgets
app=Flask(__name__,template_folder='templates') #知道模板文件app.debug=True
#登录验证实例class LoginForm(Form):
#不同的字段 内部包含正则表达式 html5.EmailField | html5.DateTimeField... name=simple.StringField( label='用户名', validators=[ #验证规则和错误提示信息 validators.DataRequired(message='用户名不能为空.'), validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d') ], widget=widgets.TextInput(), #前端页面显示的插件.TextArea render_kw={'class': 'form-control'} #设置form标签的class信息 )
# 不同的字段 内部包含正则表达式 html5.EmailField | html5.DateTimeField... pwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空.'), validators.Length(min=8, message='用户名长度必须大于%(min)d'),#自定义验证规则 validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[$@$!%*?&])[A-Za-zd$@$!%*?&]{8,}", message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
 ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} )
@app.route('/login/', methods=['GET', 'POST'])def login():if request.method == 'GET': form = LoginForm() #实例化 form验证类return render_template('login.html', form=form)else: form = LoginForm(formdata=request.form)if form.validate(): #判断是否验证成功?print('用户提交数据通过格式验证,提交的值为:', form.data)else:print(form.errors)return render_template('login.html', form=form)
if__name__ == '__main__': app.run()
app01.py
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><h1>登录</h1><form method="post" novalidate><!--<input type="text" name="name">--><p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p>
<!--<input type="password" name="pwd">--><p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p><input type="submit" value="提交"></form></body></html>
login.html
login.html

 

用户注册页面验证 

#用户注册from flask import Flask, render_template, request, redirectfrom wtforms import Formfrom wtforms.fields import corefrom wtforms.fields import html5from wtforms.fields import simplefrom wtforms import validatorsfrom wtforms import widgets
app = Flask(__name__, template_folder='templates')app.debug = True
class RegisterForm(Form): name = simple.StringField( label='用户名', validators=[ validators.DataRequired() ], widget=widgets.TextInput(), render_kw={'class': 'form-control'}, default='张根'#设置input标签中默认值 )
 pwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空.') ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} )
 pwd_confirm = simple.PasswordField( #第二次输入密码 label='重复密码', validators=[ validators.DataRequired(message='重复密码不能为空.'), validators.EqualTo('pwd', message="两次密码输入不一致") #验证2次输入的密码是否一致? ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} )
 email = html5.EmailField( label='邮箱', validators=[ validators.DataRequired(message='邮箱不能为空.'), validators.Email(message='邮箱格式错误') ], widget=widgets.TextInput(input_type='email'), #生成email input标签 render_kw={'class': 'form-control'} )
 gender = core.RadioField( label='性别', choices=( #choice radio选项 (1, ''), (2, ''), ), coerce=int #讲用户提交过来的 '4' 强制转成 int 4 ) city = core.SelectField( label='城市', choices=( ('bj', '北京'), ('sh', '上海'), ) )
 hobby = core.SelectMultipleField( #select 下拉框多选框 label='爱好', choices=( (1, '篮球'), (2, '足球'), ), coerce=int )
 favor = core.SelectMultipleField( label='喜好', choices=( (1, '篮球'), (2, '足球'), ), widget=widgets.ListWidget(prefix_label=False), #生成Checkbox 多选框 option_widget=widgets.CheckboxInput(), coerce=int, default=[1, 2] )
def__init__(self, *args, **kwargs): #重写form验证类的__init__方法可以实时同步数据中数据 super(RegisterForm, self).__init__(*args, **kwargs) self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球'))
def validate_pwd_confirm(self, field): #wtforms验证 钩子函数""" 自定义pwd_confirm字段规则,例:与pwd字段是否一致 :param field: :return:"""# 最开始初始化时,self.data中已经有所有的值
if field.data != self.data['pwd']:# raise validators.ValidationError("密码不一致") # 继续后续验证raise validators.StopValidation("密码不一致") # 不再继续后续验证
@app.route('/register/', methods=['GET', 'POST'])def register():if request.method == 'GET': form = RegisterForm(data={'gender': 1}) #默认值return render_template('register.html', form=form)else: form = RegisterForm(formdata=request.form)if form.validate():print('用户提交数据通过格式验证,提交的值为:', form.d
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_40659982/article/details/88071549
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-08 16:27:36
  • 阅读 ( 861 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢