1.flask介绍
flask:
- 轻,短小精悍
- 快,三行代码开启服务
- 自带组件少,大多数来源第三方,flask-admin,flask-session
- flask大版本更新,组件更新速度慢
django:
- 大而全,admin,models,Form,中间件
- 一个框架解决所有问题
- 一旦启动,所有资源全部加载
- 太大,结构复杂
- 所有组件都有django组件自身控制
tornado:
- 原生websocket
- 异步IO
- 非阻塞
- 几乎无三方及原生组件,连session都不支持
flask常用扩展包
Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架
2.开启flask
2.1简单运行 ----->(先通过终端安装flask(版本号1.0.2))
尝试运行:
from flask import Flask app = Flask(__name__) # 模块名称将会作为单独应用启动还是作为模块启动而有不同,只有这么起名,Flask才知道去哪里找模板,静态文件等 @app.route("/") # 使用route装饰器告诉Flask什么样的URL可以出发我们的视图函数 def index(): return "hello flask"
# 这里常规写法还是加上if __name__ == "__main__"比较好,确保服务器只会在该脚本被python解释器执行的时候运行,而非作为模板导入的时候
效果
3.render_template,redirect,HttpResponse,jsonify
3.1 HttpResponse
@app.route("/") def index(): return "hello flask" # 这里的return等同HttpResponse,直接返回字符串
3.2 Redirect
和django中的一样,用于重定向
from flask import Flask,redirect app = Flask(__name__) @app.route('/index') def index(): return redirect("/") # 跳转到根目录页面 @app.route('/') def main(): return "ok" if __name__ == "__main__": app.run("0.0.0.0",5005,debug=True)
当我们访问url: http://127.0.0.1:5000/index的时候,它会触发redirect("/")跳转到该地址,并触发对应的视图函数main
3.3 render_template
这里的render_template等同我们django中的render,不过在此我们需要创建一个html标签来接收
这里需要创建一个在同级目录下创建一个templates文件(必须叫它,源码规定),用于存放我们的html标签
from flask import Flask,render_template app = Flask(__name__) @app.route('/index') def index(): return render_template("index.html") if __name__ == "__main__": app.run("0.0.0.0",5005,debug=True)
说明:
这里一般需要指定我们的templates路径,否则会飘黄,因为模板语言采用的是jinja2,而django采用的模板语言是django,我们需要进行设置,或者选择在setting中设置
3.4 jsonify
使用 Flask 写一个接口时候需要给客户端返回 JSON 数据,在 Flask 中可以直接使用 jsonify 生成一个 JSON 的响应
from flask import Flask,jsonify app = Flask(__name__) # 返回JSON @app.route('/demo') def demo(): json_dict = { "user_id": 10, "user_name": "laowang" } return jsonify(json_dict) if __name__=="__main__": app.run(debug=True)
效果:
# 不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,如果是 JSON 需要指定 content-type:application/json
4. 关于request
4.1 简单说明
django的接口是依据uwsgi
flask依赖一个实现wsgi协议的模块:werkzeug
flask使用了werkzeug
库中的Map
和Rule
来管理url与处理函数映射关系
它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等。
from werkzeug.wrappers import Request, Response from werkzeug.serving import run_simple @Request.application def hello(request): print(request) # <Request 'http://localhost:4000/' [GET]> print(request.method) # GET print(request.url) # http://localhost:4000/ print(dir(request)) # 获取所有的方法 return Response('Hello World!') if __name__ == '__main__': run_simple('localhost', 4000, hello) # 执行该函数
4.2 request下常用参数说明:
request.method # 前端用什么方式提交,常见是GET和POST request.form # Form表单中传递过来的值使用 request.form 中拿到,打印request.form,值 ImmutableMultiDict([('user', 'learning'), ('pwd', '666')]),可看做成字典 request.args # url中传递的参数,即get请求中问号结尾后面的数据,类似django中的request.get,原始样式ImmutableMultiDict([('id', '2')]) reques.values # 获取所有参数,打印值 CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '20')]), ImmutableMultiDict([('user', 'learning'), ('pwd', '666')])]) # 它可以通过打印 request.values.to_dict() 把值全部转化成字典形式 # 从这里可以看出,有些情况下url中的key和form中的key会重名,此时会出现覆盖的情况,生产环境中一定要注意该情况(form中的key会覆盖url中的key) request.cookies # 存在浏览器端的字符串儿也会一起带过来 request.heads # 获取请求的请求头 request.data # 将处理不了的数据类型转换成json存入data中 # 数据类型参考手册 request.files # 遇到文件上传,request.files 里面存的是你上传的文件 request.path # 获取当前的url路径 request.url # 当前url的全部路径 request.script_root # 当前url路径的上一级路径 request.url_root # 当前url的路径的上一级全部路径 request.json # 如果在请求中写入了 "application/json" 使用 request.json 则返回json解析数据, 否则返回 None
获取参数request.args的使用
from flask import Flask,request app = Flask(__name__) @app.route('/flask/') def index(): id = request.args.get('id') return '获取id是%s'% id if __name__ == "__main__": app.run(debug=True)
效果
request.file上传文件说明
- 一个 <form> 标签被标记有 enctype=multipart/form-data ,并且在里面包含一个 <input type=file> 标签。
- 服务端应用通过请求对象上的 files 字典访问文件。
- 使用文件的 save() 方法将文件永久地保存在文件系统上的某处。
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>欢迎登陆</h4> <form action="/req" method="post" enctype="multipart/form-data"> <p> <input type="file" name="file"> </p> <input type="submit" value="提交"> </form> </body> </html>
# 前端页面必须设置enctype="multipart/form-data",否则提交时会报错
app.py
from flask import Flask from flask import render_template from flask import request app = Flask(__name__) @app.route("/login") def login(): return render_template("login.html") @app.route("/req",methods=["POST","GET"]) def home(): print(request.files) # ImmutableMultiDict([('file', <FileStorage: '5.jpg' ('image/jpeg')>)]) print(request.files["file"]) # <FileStorage: '5.jpg' ('image/jpeg')> my_file = request.files["file"] print(type(my_file)) # <class 'werkzeug.datastructures.FileStorage'> my_file.save("aa.jpg") # 这里写的有问题,图片过来名字就换了,而且还需判断发送的文件类型 return "ok" if __name__ == '__main__': app.run(port=5990, debug=True)
# 这里写的文件保存这里写的比较粗略,详细介绍可参考源码说明
5. 关于response
视图函数中可以返回的类型:
字符串,返回的字符串其实底层将这个字符串包装成了一个‘Response’对象
元祖,和字符串一样
response及其子类
如何返回其他类型呢??这就需要我们自定义一个Response对象,他继承自Response,套用了多继承下BaseResponse的force_type方法
from flask import Flask,url_for,Response,jsonify app = Flask(__name__) class JsonResponse(Response): @classmethod def force_type(cls, response, environ=None): ''' 这个方法只有视图函数返回非字符、非元祖、非Response对象才会调用 ''' #把字典转换成json if isinstance(response,dict): #jsonify将字典转换成json对象,还将该对象包装成了一个Response对象 response = jsonify(response) return super(JsonResponse, cls).force_type(response,environ) app.response_class = JsonResponse # 指定app.response_class为你自定义的Response对象 @app.route('/list1/') def list1(): return Response('list1') #合法对象,可以直接返回 @app.route('/list3/') def list3(): return {'username':'learning','age':22} #返回的是非字符非元祖非Response对象,执行force_type方法 if __name__ == "__main__": app.run(port=5225,debug=True)
效果
6. 关于__name__的说明
app1下: import app2 print("这在app1中",__name__) app2下: print("app2",__name__)
这里我在app1下打印:
# 这里需要强调的是,如果是在自己的文件下,__name__就是__main__,如果是从其他文件导入进来,则__name__就是它的文件名