1.概念介绍
WSGI: 全称Web Server Gateway Interface,web服务器网关接口,实际上就是一种协议,我们的应用(Django,Flask)实现了WSGI。
Werkzeug服务:实现wsgi协议的模块,本质是socket服务端,用于接收http请求并对请求进行预处理,然后触发Flask框架。
jinja2模板:可以对响应数据做模板化处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。也就是说,也可以不处理。
Flask框架:一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,flask依赖wsgi
默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。
2.安装
pip install flask
3.基本使用
0>示例
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
debug=True:表示代码有修改后,服务自动重启
__name__:是一个变量。前后加了爽下划线是因为是因为这是系统定义的名字。普通变量不要使用此方式命名变量。标识模块 的名字的一个系统变量。这里分两种情况:假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名 字就是__main__,通过if判断这样就可以执行“__mian__:”后面的主函数内容;假如此模块是被import的,则此模块 名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__:”后面的内容。
import :是要执行所import的模块的
设置json编码格式:如果为False 就不使用ascii编码:app.config['JSON_AS_ASCII']=False
设置响应头信息Content-Type:app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" (注意 ;charset=utf-8)
1> 实例化Flask对象时,可选参数的使用说明
实例化一个Flask对象,这是基本的写法:
app=Flask(__name__)
但是它还有很多的可选参数
Flask(
import_name,
#__name__
static_url_path,
#静态文件的地址前缀,写成什么,访问静态文件时,就要在前面加上这个,例如:app = Flask(__name__,template_folder='templates',static_url_path='/xxxxxx')
template_folder,
#模板所在文件夹的名字
instance_path,
#用来找配置文件的,指定from_pyfile查询文件的路径,不设置时,默认寻找和app.run()的执行文件同级目录下的instance文件夹;如果配置了instance_path(注意需要是绝对路径),就会从指定的地址下里面的文件
instance_relative_config,
#用来找配置文件的,默认为False,当设置为True时,from_pyfile会从instance_path指定的地址下查找文件。
root_path
#可以不用填,会自动找到,当前执行文件,所在目录地址
)
绑定路由的两种方式
本质是将url和视图函数封装成一个Rule对象,添加到Flask的url_map字段中
方式一:最简单的方式
from flask import Flask
app=Flask(__name__)@app.route('/test1',methods=['GET'])
def hello_world():
return 'hello world1=====11111'if __name__ == '__main__':
app.config['JSONIFY_MIMETYPE']="application/json;charset=utf-8"
app.run(debug=True)
方式二:通过app.add_url_rule()调用路由
from flask import Flask
app=Flask(__name__)def hello_world2():
return 'hello world2=====22222'app.add_url_rule(rule='/test2',view_func=hello_world2, methods=["GET"])
if __name__ == '__main__':
app.config['JSONIFY_MIMETYPE']="application/json;charset=utf-8"
app.run(debug=True)
其他特别的方式:
@app.route('/<name>') #设置url传参数 http://127.0.0.1:5000/zhanggen
def first_flask(name):
@app.route('/<int:age>/') #设置url传参数 http://127.0.0.1:5000/18/
def first_flask(age):
@app.route('/<float:salary>/') #设置url传参数http://127.0.0.1:5000/2345555.8889/
def first_flask(salary):
@app.route('/<path:url>/') #设置url传参数:http://127.0.0.1:5000/http://www.baiu.com/
def first_flask(url):
参数含义:
@app.route和app.add_url_rule参数: rule, URL规则 view_func, 视图函数名称 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 endpoint=None, 名称,用于反向生成URL,即: url_for('名称') methods=None, 允许的请求方式,如:["GET","POST"] strict_slashes=None, 对URL最后的 / 符号是否严格要求, 如: @app.route('/index',strict_slashes=False), #当为False时,url上加不加斜杠都行 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 @app.route('/index',strict_slashes=True) #当为True时,url后面必须不加斜杠 仅访问 http://www.xx.com/index redirect_to=None, 由原地址直接重定向到指定地址,原url有参数时,跳转到的新url也得传参,注意:新url中不用指定参数类型,直接用旧的参数的类型 如: @app.route('/index/<int:nid>', redirect_to='/home/<nid>') # 访问index时,会直接自动跳转到home,执行home的函数,
不执行index的 或 def func(adapter, nid): return "/home/888" @app.route('/index/<int:nid>', redirect_to=func)
2>装饰器
概念:
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能
#给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()
其中*args:可变参数的用法,允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple(元组)
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum#聪明方法,可以在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
其中**kwargs:关键字参数用法,允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict(字典)
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
之所以要加*args,**kwargs,是因为函数有千千万,你只管你自己的函数,别人的函数参数是什么样子,鬼知道?还好Python提供了可变参数*args
和关键字参数**kwargs
,有了这两个参数,装饰器就可以用于任意目标函数了。
3>请求
request.method: 获取请求方法
request.json
request.json.get("json_key"):获取json数据 **较常用
request.args.get('name') :获取get请求参数
request.form.get('name') :获取POST请求参数
request.url:获取访问url地址,例如http://127.0.0.1:5000/?age=18;
request.base_url:获取访问url地址,例如 http://127.0.0.1:5000/;
4>响应
return "字符串" :响应字符串
return render_template('html模板路径',**{}):响应模板,例如:
render_template("login.html",msg="用户名或者密码错误")
return redirect('/index.html'):跳转页面或者路径
路径:redirect("/index")
响应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",)
5>flask的cbv视图
CBV(class base views) 就是在视图里使用类处理请求。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
def auth(func):
def inner(*args, **kwargs):
result = func(*args, **kwargs)
return result
return innerclass IndexView(views.MethodView):
# methods = ['POST'] #只允许POST请求访问
decorators = [auth,] # 如果想给所有的get,post请求加装饰器,就可以这样来写,也可以单个指定def get(self): #如果是get请求需要执行的代码
v = url_for('index')
print(v)
return "GET"def post(self): #如果是post请求执行的代码
return "POST"app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) #name即FBV中的endpoint,指别名
if __name__ == '__main__':
app.run()
6>Jinja2模板
Flask使用的是Jinja2模板,这里不感兴趣,就没有学习
7>Session
除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥
- 设置:session['username'] = 'xxx'
- 删除:session.pop('username', None)
#coding=utf-8
from flask import Flask,render_template,request,redirect,session
import json
app = Flask(__name__)
app.secret_key = "sdsfdsgdfgdfgfh" # 设置session时,必须要加盐,否则报错def wrapper(func):
def inner(*args,**kwargs):
if not session.get("user_info"):
return redirect("/login")
ret = func(*args,**kwargs)
return ret
return inner@app.route("/login",methods=["GET","POST"],strict_slashes=False) # 指定该路由可接收的请求方式,默认为GET
def login():
if request.method=="POST":
return 'post method is not support'
else:
username = request.args.get("username")
password = request.args.get("password")
if username=="ssj" and password=="123":
session["user_info"] = username
# session.pop("user_info") #删除session
return redirect("/index")
else:
# return render_template("login.html",**{"msg":"用户名或密码错误"})
return json.dumps({'msg':'用户名或者密码错误'})@app.route("/index",methods=["GET","POST"],strict_slashes=False)
@wrapper #自己定义装饰器时,必须放在路由的装饰器下面
def index():
# if not session.get("user_info"):
# return redirect("/login")
username=session.get("user_info")
return 'index.html is ok,'+username
if __name__ == '__main__':
app.run(debug=True)
- Django中,session保存在服务端的数据库中,数据库中保存请求用户的所有数据,服务端数据中{'随机字符串':加密后的客户相关信息},请求完成后,把随机字符串作为值,返回给客户端,保存在客户端的cookie中,键为:sessionid,值为:服务端返回的随机字符串;即{'sessionid':'随机字符串'}
- Flask中,服务端什么都不存,用户第一次请求时,在内存中生成一个空字典,将这个空字典加密后,返回给客户端,保存在客户端的cookie中,键为’session',值为:加密后的字典,下次访问时,读取客户端cookie中key为session对应的值,然后进行解密(如果不能按之前的的加密方式对应个解密方式解密,即认为第一次请求,重新生成空字典),解密成功后,可以对字典进行操作,保存新数据在字典中,请求完成后,会重新加密这个字典,返回个客户端保存
8>flash 闪现
message是一个基于Session实现的用于保存数据的集合,其特点是:一次性。不长期占用内存。
session存在在服务端的一个字典里面,session保存起来,取一次里面还是有的,直到你删除之后才没有了
本质
flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅可以拿到值,而且可以把其从session里的去掉,
基于Session实现的用于保存数据的集合,其特点是:使用一次就删除。
from flask import flash,get_flashed_messages
flash({'user_info':username}) #添加username=get_flashed_messages()#获取并删除
print(username)
9>中间件
在函数执行之前或函数执行之后想做点事情,有2种方式
第一种:装饰器
第二种:flask里面的扩展,相当于django中的中间件
flask也有中间件功能和Django类似,不同的是使用的是使用3个装饰器来实现的;
1.@app.before_first_request :请求第1次到来执行1次,之后都不执行;
2.@app.before_request:请求到达视图之前执行;(改函数不能有返回值,否则直接在当前返回)
3.@app.after_request:请求 经过视图之后执行;(最下面的先执行)
未完待续