Web服务器
Flask简介
Flask三剑客
数据处理
请求对象
Flask特点
Flask文件上传案例
第一个Flask程序
开启DEBUG模式
配置DEBUG的几种方式
URL
基础示例
带参数示例
path全部路径
uuid匹配
any多路径
接收前端传递的parmas
url_for
url转换器
自定义url转换器
自定义url转换器数据处理
自定义转换器处理url
重定向
函数视图Response
返回一个合法对象
返回一个字符串
返回一个元祖
函数视图装饰器
flask路由对象参数
flask实例化配置
flask对象配置
Web服务器
web服务器:负责处理http请求,响应静态文件,常见的有Apache,Nginx以及微软的IIS;
应用服务器:负责处理逻辑的服务器。比如php、python的代码,是不能直接通过nginx这种web服务器来处理的,只能通过应用服务器来处理,常见的应用服务器有uwsgi、tomcat等;
web应用框架:一般使用某种语言,封装了常用的web功能的框架就是web应用框架,flask、Django以及Java中SSH(Structs2+Spring3+Hibernate3)框架都是web应用框架;
Flask简介
flask是一款非常流行的Python Web框架,出生于2010年,作者是Armin Ronacher,本来这个项目只是作者在愚人节的一个玩笑,后来由于非常受欢迎,进而成为一个正式的项目。目前为止最新的版本是0.12.2。
flask自2010年发布第一个版本以来,大受欢迎,深得开发者的喜爱,并且在多个公司已经得到了应用,flask能如此流行的原因,可以分为以下几点;
Flask三剑客
httpresponse:直接返回一个string即可;
render:使用render_template返回一个html文件;
redirect:使用redirect返回一个url;
数据处理
jsonify:直接序列化成json字符串并且在返回头部将Content-Type修改为json;
send_file:返回一个文件,不限于jpg,txt,mp4,并且会自动修改Content-Type;
请求对象
args:获取url参数;
form:获取Formdata中的数据;
to_dict:将数据转换成字典;
url:获取访问完整路径;
method:获取请求方式;
path:获取路由地址;
host:获取主机地址;
host_url:获取访问主机地址;
json:如果提交时请求头中的Content-Typ为json就会自动序列化成json字符串,就不会reque里面呈现了;
data:如果请求提交的Content-Typ对应的值不认识,那么就以原始形式呈现,原始就是bytes;
valeus:将args和fromdata都获取到一个字典里面,通常不用来获取数据;
files:拿到一个文件对象;
filename:文件名;
save:保存文件;
cookies:获取cookice;
headers:获取请求头;
Flask特点
1、微框架、简洁、只做他需要做的,给开发者提供了很大的扩展性;
2、Flask和相应的插件写得很好,用起来很爽;
3、开发效率非常高,比如使用SQLAlchemy的ORM操作数据库可以节省开发者大量书写sql的时间;
4、Flask的灵活度非常之高,他不会帮你做太多的决策,一些你都可以按照自己的意愿进行更改。比如;
5、使用Flask开发数据库的时候,具体是使用SQLAlchemy还是MongoEngine,选择权完全掌握在你自己的手中。区别于Django,Django内置了非常完善和丰富的功能,并且如果你想替换成你自己想要的,要么不支持,要么非常麻烦;
6、把默认的Jinija2模板引擎替换成其他模板引擎都是非常容易的;
Flask文件上传案例
Flask接收到前端上传的文件的时候,可以直接使用save方法,保存文件到指定的路径,并且使用send_file或者send_from_directory方法直接返回一个文件,flask会自动判断文件类型,修改header里面的Content-type;
// a
from flask import Flask, request, render_template, redirect, send_from_directory, send_file
import os
app = Flask(__name__)
@a('/upload', methods=['GET', 'POST'])
def upload():
if reque == 'GET':
return render_template('u;)
file = reque('file') # 获取到文件的form源数据
('images', )) # 直接save到images目录下
return redirect('/images/%s' % ) # 直接返回上传的图片
@a('/images/<filename>')
def images(filename):
print('images', filename))
return send_from_directory('images', filename) # 或者send_file('images', filename))
if __name__ == '__main__':
a(debug=True, port=80)
// u
<body>
<div>
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="file">文件上传</label>
<input type="file" name="file" id="file">
<input type="submit" name="提交">
</form>
</div>
</body>
第一个Flask程序
from flask import Flask # 导入Flask类
app = Flask(__name__) # 使用Flask类生成一个实例对象,__name__主要的作用是可以规定默认和静态文件的路径
@a('/') # 这是一个装饰器,主要用于添加url路由,将url中的/映射到hello_world这个视图函数
def hello_world(): # 创建请求处理视图
return 'Hello World!' # 默认回复一个string就是一个HttpResponse
if __name__ == '__main__':
a() # 它是一个测试服务器,run起来之后就会启动一个带有Flask的应用服务器
开启DEBUG模式
开启DEBUG模式的作用可以做代码调试,当我们在项目运行的过程中出现异常的时候,如果我们开启了DEBUG模式可以查看到详细的报错,想到到哪一个文件哪一行,那么还有另一个好处,就是每当项目主代码发生变更,就会自动重启,给我们的带来更好的开发体验;
配置DEBUG的几种方式
1、直接在a()传递一个debug=true即可;
2、可以使用a(DEBUG=True),直接修改app对象的配置也可以做到开启DEBUG模式;
3、可用使用a也可以修改debug模式;
4、使用对象的模式进行修改,可以创建一个py文件,然后写入DEBUG=True,并且导入a,然后是flask主文件里面使用a(mode)进行导入;
5、可以创建一个文件(不局限于py文件),然后写入DEBUG=True,这种方式不需要以模块的方式导入,然后是flask主文件里面使用a)进行导入;
URL
URL的在Flask中用@ar()来定义,它主要用于,指定的URL对应的处理函数,并且还可以带上参数,指定不同的参数,来加载不同的数据;
基础示例
@a('/list') # 定义一个url访问路径为/list,对应的处理函数为这个装饰器下面的函数
def article_list():
return 'article_list'
带参数示例
带参数就是可以对url中的路径进行正则匹配,比如,那么后面的1就是一个参数,示例如下;
@a('/detail/<int:id>') # 表示这个参数为一个int类型,默认为string,所以可以不用指定类型,并且将这个参数传递给id这个变量
def article_detail(id): # 既然带了参数,那么我们的视图函数就得需要加入一个参数,此处用ID来接收
print(id)
return 'article_detail'
path全部路径
path可以接收,匹配到的这个uri到最后的位置,比如我们此时访问的是https://server_name:port/detail/info/1,那么path匹配到的是info/1,可以包含/;
@a('/detail/<path:url>') #
def article_detail(url): # 匹配全部路径
print(url)
return 'article_detail'
uuid匹配
使用uuid来规划url,所以传入的必须是一个uuid;
@a('/detail/<uuid:id>')
def article_detail(id):
print(id)
return 'article_detail'
any多路径
any可以指定多路径匹配,比如访问/detail/1和/article_detail/1我们就可以使用any(article_detail,detail)来匹配,示例如下;
@a('/<any(person,article):types>/<int:id>')
def detail(types,id):
if types =='person':
return 'person'+str(id)
return 'article' + str(id)
接收前端传递的parmas
@a('/')
def hello_word():
page=reque('page')
print(page)
return 'Hello Word!'
url_for
比如现在我们可以拿到一个视图函数,那么我们就可以通过url_for来找到对应是url,并且还可以带上参数,示例如下;
from flask import Flask,request,url_for
app = Flask(__name__)
@a('/')
def hello_word():
print(url_for('detail',id=1)) # 必须带上参数,并且要以位置参数的形式传递,如果传递的参数过多,那么多余的参数会以parmas的方式展现
return 'Hello Word!'
@a('/detail/<id>') # 定义一个参数id
def detail(id):
return 'detail'
url转换器
1、转换器是一个类,且必须继承BaseConverter;
2、转换器中实现to_python方法,这个方法的返回值将会传递view中作为参数,也就是修改这个转换器的值;
3、在转换器中实现to_url,这个方法的返回值将会在调用url_for的时候生成符合要求的url形式;
自定义url转换器
我们的url参数匹配有int、any、string等,这些限制都是在“from werkzeug.routing import BaseConverter”这类里面实现的那么我们也可以自定义这些规则,然后进行规则匹配;
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/10/9 10:25
# @Author : CaiChangEn
# @Email : mail0426@163.com
# @Software: PyCharm
from flask import Flask,request,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class cce(BaseConverter):
regex = r'1[384]\d{9}$' # 规定正则为以1开头后面跟着cce然后以一个数字结尾;
a['cce']=cce # 将自定义规则加入到flask默认规则里面
@a('/<cce:test>') # 测试规则
def hello_word(test):
return 'Hello Word!'
if __name__ == '__main__':
a(port=80, debug=True)
自定义url转换器数据处理
可以看到,我们flask内置了几种数据类型的转换器,比如有int/string等,如果flask内置的转换器不能满足你的需求,我们就需要自定义转换器,需要满足几个条件:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/10/9 10:25
# @Author : CaiChangEn
# @Email : mail0426@163.com
# @Software: PyCharm
from flask import Flask,request,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class cce(BaseConverter):
regex = r'1[384]\d{9}$' # 规定正则为以1开头后面跟着cce然后以一个数字结尾;
def to_python(self, value):
return value[0:3]
a['cce']=cce # 将自定义规则加入到flask默认规则里面
@a('/<cce:test>') # 测试规则
def hello_word(test):
return 'Hello Word!'+test
if __name__ == '__main__':
a(port=80, debug=True)
自定义转换器处理url
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/10/9 10:25
# @Author : CaiChangEn
# @Email : mail0426@163.com
# @Software: PyCharm
from flask import Flask,request,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class cce(BaseConverter):
regex = r'1[384]\d{9}$'
def to_python(self, value):
return value
def to_url(self, value): # url转换
return 'cce1'
a['cce']=cce
@a('/') # 测试规则
def hello_word():
print(url_for('c1',test=)) # url引用
return 'Hello Word!'
@a('/cce/<cce:test>') # 规则限定
def c1(test):
return 'cce'
if __name__ == '__main__':
a(port=80, debug=True)
重定向
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向);
flask是通过(location,code=302)这个函数来实现重定向的,location是需要重定向到的url,应该配合之前讲的在url_for()函数来使用,code表示哪种重定向,默认302,也即暂时性重定向,301是永久性重定向.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/10/9 10:25
# @Author : CaiChangEn
# @Email : mail0426@163.com
# @Software: PyCharm
from flask import Flask,request,url_for,redirect
app = Flask(__name__)
@a('/')
def home():
return redirect(';,code=301)
if __name__ == '__main__':
a(port=80, debug=True)
函数视图Response
视图函数的返回值会被自动转换为一个响应对象,Flask的逻辑如下
1、如果返回的是一个合法的响应对象,则直接返回;
2、如果返回的是一个字符串,那么Flask会重新创建一个werkzeug.wra对象,Response将该字符串作为主体,状态码为200,MIME类型为text/html,然后返回该Response对象;
3、如果返回的是一个元组,元组中的数据类型是(response,status,headers)。status会覆盖默认的200状态码,headers可以是一个列表或者字典作为额外的消息头;
4、如果以上条件都不满足,Flask会假设返回值是一个合法的WSGI应用程序,并通过Re(rv,reque)转换为一个请求对象;
返回一个合法对象
可以使用make_response函数来创建Response对象,这个方法可以设置额外的数据,比如cookie、header信息等;
from flask import Flask,request,url_for,redirect,make_response
app = Flask(__name__)
@a('/')
def home():
return make_response('make_response')
if __name__ == '__main__':
a(port=80, debug=True)
# 或者
from flask import Flask,request,url_for,redirect,Response
app = Flask(__name__)
@a('/')
def home():
return Response('Response')
if __name__ == '__main__':
a(port=80, debug=True)
返回一个字符串
返回一个字符串的时候,Flask在构建响应报文的时候会自动将这个字符串转换成httpresponse;
from flask import Flask,request,url_for,redirect,Response
app = Flask(__name__)
@a('/')
def home():
return 'Response'
if __name__ == '__main__':
a(port=80, debug=True)
返回一个元祖
返回一个元祖,那么元素内部可以有三个参数,第一个是一个httpresponse对象,第二个是状态吗,第三个是传参;
from flask import Flask,request,url_for,redirect,Response
app = Flask(__name__)
@a('/')
def home():
return (Response('11'),222,{'token':'asdasdsadasdadasdassdsadadsasda'})
if __name__ == '__main__':
a(port=80, debug=True)
函数视图装饰器
一下用一个登录的装饰器,来演示函数视图加入装饰器的简单使用,注意,wraps是必须的,否则,endpoint会相同导致项目无法启动;
自己写的装饰必须在,a的下面,因为装饰器是修饰下面的函数,下面,如果放到a的上面,那么就修饰的a;
from flask import Flask, request, Response
from functools import wraps
app = Flask(__name__)
def login_required(func):
@wraps(func)
def wapper(*args, **kwargs):
if reque('username', None):
return func(*args, **kwargs)
else:
return '你没有携带必要的参数'
return wapper
@a('/')
@login_required
def home():
return 'home'
if __name__ == '__main__':
a("0.0.0.0", port=80, debug=True)
flask路由对象参数
endpoint:反向生成url地址标志,默认为视图函数名,可以路由url_for函数来解析;
methods:视图函数允许请求的方式,默认为GET;
defaults:默认参数;
strict_slashes:bool值,是否严格遵循路由地址,也就是访问的时候是否需要带上/;
/index/<[int|string]:page>:动态路由参数;
flask实例化配置
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录
static_host = None, # 远程静态文件所用的Host地址,默认为空
static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用
# host_matching是否开启host主机位匹配,是要与static_host一起使用,如果配置了static_host, 则必须赋值为True
# 这里要说明一下,@a("/",host="localhost:5000") 就必须要这样写
# host="localhost:5000" 如果主机头不是 localhost:5000 则无法通过当前的路由
host_matching = False, # 如果不是特别需要的话,慎用,否则所有的route 都需要host=""的参数
subdomain_matching = False, # 理论上来说是用来限制SERVER_NAME子域名的,但是目前还没有感觉出来区别在哪里
template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录
instance_path = None, # 指向另一个Flask实例的路径
instance_relative_config = False # 是否加载另一个实例的配置
root_path = None # 主模块所在的目录的绝对路径,默认项目目录,就是我们的__name__
flask对象配置
'DEBUG': False, # 是否开启Debug模式
'TESTING': False, # 是否开启测试模式
'PROPAGATE_EXCEPTIONS': None, # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True
'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一两句话说不清楚,一般不用它
'SECRET_KEY': None, # 之前遇到过,在启用Session的时候,一定要有它
'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命周期(天)默认31天
'USE_X_SENDFILE': False, # 是否弃用 x_sendfile
'LOGGER_NAME': None, # 日志记录器的名称
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None, # 服务访问域名
'APPLICATION_ROOT': None, # 项目的完整路径
'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字
'SESSION_COOKIE_DOMAIN': None, # 在哪个域名下会产生session记录在cookies中
'SESSION_COOKIE_PATH': None, # cookies的路径
'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否应被设置 httponly 的标志,
'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否应被设置安全标志
'SESSION_REFRESH_EACH_REQUEST': True, # 这个标志控制永久会话如何刷新
PERMANENT_SESSION_LIFETIME:设置session的过期时间,默认30天;
'MAX_CONTENT_LENGTH': None, # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码
'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默认缓存控制的最大期限
'TRAP_BAD_REQUEST_ERRORS': False,
# 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样,
# 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。
'TRAP_HTTP_EXCEPTIONS': False,
# Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。
# 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。
# 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。
# 如果这个值被设置为 True ,你只会得到常规的回溯。
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http', # 生成URL的时候如果没有可用的 URL 模式话将使用这个值
'JSON_AS_ASCII': True,
# 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False ,
# Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。
# 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。
'JSON_SORT_KEYS': True,
#默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。
# 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。
# 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,