快速开始
安装flask
pip install flask
依赖
werkzeug:一个WSGI工具包(web服务网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为python语言定义的web服务器和web应用程序或框架之间的一种简单而通用的接口
jinja2:模板引擎
from flask import Flask # Flask是核心类
# 初始化application
app=Flask(__name__)
# 运行服务器
app.run()
定义路由
@app.router("/")
def index():
return "hello world"
处理url和函数之间的绑定关系的程序叫做路由。
视图函数
处理url的逻辑和方法,就叫视图函数。
@app.router("/")
def index(): # 视图函数
return "hello world"
请求
- 请求数据存在request里
- 获取请求数据
@app.route('/')
def index():
args=request.args
name=args.get("name")
print(name)
return 'Hello World!'
访问:http://127.0.0.1:5000/ name的值为None
访问:http://127.0.0.1:5000?name=joy name的值为joy
使用request.args.get(key)获取get请求的参数。
响应
return 后面是响应内容。 可以是json、html、html文件、str
-
字符串文本
return 'Hello World!' -
html
return '<h1>Hello html</h1>' -
html文件
from flask import Flask,request,render_template @app.route('/') def index(): return render_template("index.html")html文件需要放在
templates文件夹下。why?app初始化时:
template_folder="templates"static_folder:项目静态文件放置,如css.image等static_url_path:前端访问时,告知静态文件存放的文件夹存储图片小技巧(页面展示图片、做个人博客图片等):
将图片存储在
static中,可以通过127.0.0.1:5000/static/hello.jpg访问图片 -
json
MVC组成
-
model --》数据相关逻辑,sql
-
view --》前端内容,response html
-
control --》控制器,视图函数,作用:接收请求+响应结果
-
控制器 Controller :负责转发请求、对请求进行处理
-
视图 View:界面设计人员进行图形界面设计
-
模型 Model:程序员编写程序应有的功能(实现算法等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)
@app.route('/') def hello_world(): # 1. 接收参数 # 2. 调用对应的函数去处理数据--》model # 3. 构建响应结果 return 'Hello World!'
开启服务器
-
使用
app.run(),app.run(debug=True)调试模式,开启后代码修改后会自动重启服务。只能在测试、开发环境使用,不能在生产环节使用debug模式。 -
命令行运行:
set FLASK_APP=app.py、flask run
比如host、post参数都在run里指定参数,但是他们也可以通过配置文件的形式来修改。
配置文件的必要性:
如果现在要部署给别人用,debug这样的东西就要关掉,port这些东西也又可能修改,那是不是上线以后再手动修改呢?
不是,而是通过配置文件,不同的环境我们使用不同的配置文件就可以了。
配置参数的方式:
- 字典、元组
- 反射 setattr\getattr
- config文件
- Config类 后面讲
### 配置项
app.config["DEBUG"]=True
app.config["PORT"]=5002
@app.route('/')
def index():
args=request.args
name=args.get("name")
print(name)
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=app.config["DEBUG"],port=app.config["PORT"])
注意事项
host
其他网络访问:0.0.0.0外部访问。所有人可访问。
固定的网络地址:192.168.1.23 ,指定访问
127.0.0.1 本机可访问
路由
处理URL和函数之间的关系的程序就叫做路由。
一、多URL的路由
一个函数上可以设置多个url路由规则。
@app.route('/hello/<name>')
@app.route('/hello')
@app.route('/')
def index():
args = request.args
name = args.get("name")
print(name)
return 'Hello World!'
还有其他的装饰器,视图函数装饰器应该放在最外层,不然不会生效。
二、路由动态参数
请求参数中传递参数:
@app.route('/cases')
def cases():
id = request.args.get("id")
return '正在执行什么啊{}'.format(id)
访问:http://127.0.0.1:5002/cases?id=2
路由上传递参数:(建议使用)
@app.route('/cases/<id>')
def index(id):
print(id)
return '正在执行{}'.format(id)
访问:http://127.0.0.1:5002/cases/2
规定入参的类型:
@app.route('/cases/<int:id>')
def index(id):
print(id)
return '{}是一个整数'.format(id)
支持的类型:
int 整数
float 浮点数
string 字符串,不可以包含斜杠
path 跟字符串的区别是,可以包含斜杠
uuid 特定格式字符串,通常是生成唯一id,uuid.uuid4() 导入uuid标准库 import uuid
三、路由重定向
访问/hello,/hello/的区别
@app.route('/cases')
def cases():
return 'cases'
访问http://127.0.0.1:5002/cases 可以返回
访问http://127.0.0.1:5002/cases/ 404
@app.route('/cases/')
def cases():
return 'cases'
访问http://127.0.0.1:5002/cases 可以返回
访问http://127.0.0.1:5002/cases/ 也可以返回
抓取接口请求,访问http://127.0.0.1:5002/cases 时,调起了两个请求,分别是/cases、/cases/的.
状态码为308,永久重定向。重定向地址为Location的参数:http://127.0.0.1:5002/cases/
flask的哲学与灵活:
flask哲学:/cases和/cases代表两个不同的url地址
flask灵活:定义路由/cases/,访问/cases时 会重定向到/cases/
四、路由注册机制
- 集中注册机制 (项目大,大量url,项目大时会分布到多个模块中,而把注册规则放到一个文件中)
def cases():
return 'cases'
# 路由、view_fun参数绑定函数名
app.add_url_rule('/cases/', view_func=cases)
- 装饰器注册
@app.route('/cases/')
def cases():
return 'cases'
app.route()实际也是调用的add_url_rule()方法
- app.url_map()
路由是处理URL和函数之间的关系的程序。绑定url和函数之间的关系关系都会单独命一个名字(这个东西就叫做端点) app.url_map()专门用来存储路由关系。
app = Flask(__name__)
print(app.url_map)
def cases():
return 'cases'
app.add_url_rule('/cases/', view_func=cases)
print(app.url_map)
打印结果:
Map([<Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])
Map([<Rule '/cases/' (GET, OPTIONS, HEAD) -> cases>,
<Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])
在没有绑定路由时,咱们的路由关系就只有static的。
绑定路由后<Rule '/cases/' (GET, OPTIONS, HEAD) -> cases>端点名是cases,默认是使用视图函数的函数名作为端点名。(GET, OPTIONS, HEAD)表示支持的请求方式。
五、app.route()可配置的参数
- 添加mehtods参数:请求方式
@app.route('/', methods=["POST"])
def hello_world():
return 'Hello World!'
def cases():
return 'cases'
app.add_url_rule('/cases/', view_func=cases, methods=["POST"])
print(app.url_map)
修改了接口支持的请求方式:
Map([<Rule '/cases/' (OPTIONS, POST) -> cases>,
<Rule '/' (OPTIONS, POST) -> hello_world>,
<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
- endpoint 修改路由Mapping地址对应视图函数的端点名
@app.route('/', methods=["POST"],endpoint="hello")
def hello_world():
return 'Hello World!'
print(app.url_map)
<Rule '/' (POST, OPTIONS) -> hello>,
- redirect_to 重定向
一种是在app.route中的参数redirect_to,一种方式是在视图函数中return redirect方法。
区别,作为app.route参数redirect_to="/cases/"时,访问http://127.0.0.1:5000/ 时,程序不进入hello_world()函数中,作为return redirect("/cases/")访问http://127.0.0.1:5000/policy 时,会进入到视图函数policy()中
@app.route('/', methods=["GET", "POST"], endpoint="hello", redirect_to="/cases/")
def hello_world():
print("进入hello_world")
return 'Hello World!'
@app.route('/cases/', methods=["GET", "POST"], )
def cases():
return 'cases'
@app.route('/policy', methods=["GET", "POST"], )
def policy():
print("进入policy")
return redirect("/cases/")
- defaults 默认值,经常用在动态参数上
@app.route('/',methods=["POST","GET"])
def index():
return 'home'
@app.route('/cases',methods=["GET"],defaults={"id":3})
def cases(id):
print(id)
return redirect("/")
视图函数中可直接定义 id=3
视图函数的分离
大型项目中, 我们的架构:
- 启动文件
- 视图函数
- 数据处理
- view
- 其他的帮助函数
可能出现的问题,模块间的相互调用,会造成循环调用,解决:就是使用时再调用。
视图函数
1. 什么是视图函数
什么是视图函数
视图函数里写什么
逻辑不应该太长,具体逻辑在另外的模块去封装。
能封装整理尽快,不要等到以后,以后太乱了不会再由耐心去整理。
url--》后端逻辑
2. 视图函数的形式
分请求方法
分请求单数复数
视图函数对应mvc的部分,不要越界
# 获取所有测试用例/获取单个测试用例
# 在同一个函数中处理
# @app.route('/project')
# def project():
# if request.args.get("id") is None:
# return "all projects"
# else:
# return "单个case"
# 在不同的函数中处理
@app.route('/projects')
def projects():
return "all projects"
@app.route('/project/<id>')
def project(id):
return "单个case"
# 不同的请求方法 GET POST PUT 是在一个函数中处理 还是不同的函数中处理
# 通常是放到同一个视图函数中处理(前后端不分离)
3. 什么是基于类的视图(可插拔视图)
从django学来的
4. 类的视图有什么好处
前后端分离适用 ,前后端不分离的 常用适用一个函数处理get/post不同的请求方法
- 类是可以继承的
- 代码可以复用
- 可以定义多种行为
5. 可插拔视图
类视图有个固定的dispatch_request方法。
类视图里不能通过装饰器进行路由注册。
from flask.views import view
app =Flask(__name__)
class UserView(view):
method = ["GET","POST"]
def dispatch_request(self):
return '{}到hello'.format(request.method)
add.add_url_rule("/",view_function=UserView.as_view('user'))
把类当成方法在使用。
from flask import Flask, request
from flask.views import View
app = Flask(__name__)
class Project(View):
# 也可以把请求方法作为类的属性
# methods=["POST","GET"]
# get方法
def get(self):
return "一些get方法逻辑"
# post方法
def post(self):
return "一些post方法逻辑"
def dispatch_request(self): # 分配请求
dispatch_pattern = {"GET": self.get, "POST": self.post}
# 获取请求方法
method = request.method
print(method)
# 调用get/post方法
return dispatch_pattern.get(method)()
app.add_url_rule("/project",
view_func=Project.as_view("project"),
# 默认是get方法
methods=["POST","GET"]
)
6. 对不同的请求方法进行不同的处理
见上小节
7.methodView
methodView继承了View,实现了dispatch_request方法,所以继承methodView,可以直接写get、post方法等,不需要再写dispatch_request方法。
from flask import Flask
from flask.views import MethodView
app = Flask(__name__)
class ProjectView(MethodView):# 继承MethodView,不用使用
# get方法
def get(self):
return "一些get方法逻辑1111"
# post方法
def post(self):
return "一些post方法逻辑2222"
app.add_url_rule("/project",
view_func=ProjectView.as_view("project"),
# 默认是get方法
methods=["POST", "GET"]
)
8.methodview的例子
from flask import Flask
from flask.views import MethodView
app = Flask(__name__)
class ProjectView(MethodView): # 继承MethodView,不用使用
# get方法
def get(self, project_id):
if project_id is None:
return "获取项目列表"
else:
return "显示项目:{}".format(project_id)
# post方法
def post(self, project_id):
return "创建一个项目:{}".format(project_id)
def put(self, project_id):
return "更新项目:{}".format(project_id)
def delete(self, project_id):
return "删除项目:{}".format(project_id)
# 有参数、无参数的分开注册
f = ProjectView.as_view("projects")
app.add_url_rule("/projects/<project_id>",
view_func=f,
methods=["GET","POST", "PUT", "DELETE"]
)
app.add_url_rule("/projects",
view_func=f,
defaults={"project_id": None},
methods=["GET"]
)
请求和响应
1.请求对象
获取前端传过来的请求数据是后端服务来管理的。Flask内置实现了,使用from flask import request导入
-
get请求
request.args
@app.route('/projects') def projects(): args = request.args print(args.get("id")) return args访问:http://127.0.0.1:5002/projects?id=2 ,获取?后面的参数
args.get("id") ==>2
-
表单
form_data=request.form
-
json/header
json_data=request.json
-
file file_data =request.files
-
ajax请求
MVC
配置文件
模版引擎
表单验证
WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。
安装:pip3 install wtforms
现在使用flask拓展 Flask-WTF,Flask-WTF 提供了简单地 WTForms 的集成
全局变量
数据库和模型
ORM模型数据库操作
安装
pip install sqlalchemy
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["DEBUG"]=True
# SQLALCHEMY_DATABASE_URI格式为:数据库类型+数据库引擎+用户名+密码@ip:port/数据库
app.config["SQLALCHEMY_DATABASE_URI"]="mysql+pymysql://root:@localhost:3306/test"
# app.config["SQLALCHEMY_BINDS"]=False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]=False
db = SQLAlchemy(app) # 初始化数据库对象 、绑定app
# 设计表
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
def create_all():
return db.create_all()
create_all() #生成表
if __name__ == '__main__':
app.run()
使用命令行创建数据库:
set Flask_APP=app.py
flask shell进入flask shell ,到app的环境中
from app import db导入db
db.create_all() 创建表
使用migrate创建:
为什么用migrate 1.迁移时更加方便 2.动态修改数据库结构
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]='mysql+pymysql://root:{}@127.0.0.1:3306/test'.format("123456")
db = SQLAlchemy(app)
migrate=Migrate(app,db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
安装:pip install flask-migrate
初始化命令:flask db init,会生成一个migrations文件
命令:flask db migrate,在migrations/versions下生成一些创建数据库的脚本
更新表:flask db upgrade
删除表:flask db downgrade
使用代码创建: