Flask——接口路由技术
接口路由技术
- 一、Flask 简介
- 1、环境安装:
- 2、一个最小的应用
- 3、两种运行方式
- 二、定义路由
- 1、普通路由
- 2、动态路由
- 3、限定类型
- 4、地址尾部的“/”
- 三、请求与响应-请求方法
- 四、请求与响应-处理请求数据
- 1、request的常用属性/方法
- 2、get 请求参数
- 3、json 请求
- 4、表单请求
- 5、文件请求
- 五、请求与响应-处理响应信息
- 1、文本型
- 2、元组
- 3、Json
- 4、html
- 5、额外数据
- 六、测试平台环境配置
- 七、接口配置
- 1、flask-restx 介绍
- 2、插件安装
- 3、demo 示例
- 八、接口使用
- 1、设计框架的原则
- a、高耦合实例
- b、低内聚示例
- 2、编写 RESTFUL 风格的接口
- 3、添加路由的方式
- 方式一:
- 方式二
- 九、集成swagger
- 1、namespace 的使用
- 2、swagger 接口文档配置
- a、api.parser()用法
- b、get 请求示例
- c、post 请求示例
- 1、处理 json 格式
- 2、处理 files格式
- 3、处理 form格式
- 4、处理choice格式
- 十、orm介绍
- 1、什么是持久化
- 2、什么是 ORM
- 3、ORM 与 SQL 的对比
- 4、ORM 优缺点
- 十一、orm中间件配置
- 十二、数据库与表管理
- 创建表操作
- 删除表操作
- 十三、对象与数据模型
- 1、数据模型
- 2、设计用户表字段
- 3、Flask-SQLAlchemy 的属性字段定义
- 4、Flask-SQLAlchemy 字段常用关键字参数
- 5、Flask-SQLAlchemy 对象与数据模型示例
- 十四、数据CRUD
- 1、添加数据(create)
- a、单条数据新增
- b、多条数据新增
- 2、读取数据(read)
- a、查询表中全部数据
- b、条件查询——单条件查询
- c、条件查询——多条件查询
- 3、修改数据(update)
- 4、删除数据(delete)
- 十五、多表关系-一对多
- 1、一对多关系
- 2、一对多表结构
- 3、一对多增删查改
- a、数据新增
- b、数据查询
- 多查一
- 一查多
- c、数据修改
- 一改多
- 多改一
- d、数据删除
一、Flask 简介
Flask 是一个轻量级的 web 开发框架。 它依赖 jinja2 和 Werkzeug WSGI 服务的一个微型框架。
1、环境安装:
pip install flask
2、一个最小的应用
# 1. 导入 Flask 模块
from flask import Flask
# 2. 创建Flask应用程序实例
app = Flask(__name__)# 3. 定义路由及视图函数
@app.route("/")
def hello_world():return "<p>Hello, World!</p>"
# 4. 启动程序
if __name__ == '__main__':app.run()
3、两种运行方式
linux/mac: 命令行运行
$ export FLASK_APP=hello
$ flask run
windows: 命令运行
set FLASK_APP=app.py
flask run
代码调用
if name == ‘main’:
app.run()
二、定义路由
1、普通路由
通过装饰器 @app.route 添加路由
from flask import Flask#2、创建flask应用程序的实例;__name__==__main__
app=Flask(__name__)#添加路由
@app.route("/")
def hello_world():return "<p>hello world</p>"@app.route("/demo")
def demo():return "<p>hello world 666</p>"#启动入口
if __name__=='__main__':#flask服务启动起来#轮询等待的方式,等待浏览器发来请求#会一直接收请求,直到程序停止app.run()

2、动态路由
通过 app.route('/user/<username>') 添加动态路由
from flask import Flask#2、创建flask应用程序的实例;__name__==__main__
app=Flask(__name__)#添加路由
@app.route("/")
def hello_world():return "<p>hello world</p>"@app.route("/demo")
def demo():return "<p>hello world 666</p>"@app.route("/userinfo/<username>")
def demo1(username):return f"hello world 这是{username}同学"#启动入口
if __name__=='__main__':#flask服务启动起来#轮询等待的方式,等待浏览器发来请求#会一直接收请求,直到程序停止app.run()
3、限定类型
路径中添加 <类型:变量名> 来限定变量的类型
@app.route('/post/<int:post_id>')
string:接收任何不包含斜杠的文本
int:接收正整数
float:接收正浮点数
path:类似string,但可以包含斜杠
uuid:接收UUID字符串
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/5/26 07:03
# @Author : 杜兰特
# @File : flask_demo.py#1、导入flask模块
from log_utils import loggerfrom flask import Flask#2、创建flask应用程序的实例;__name__ ==__main__
app=Flask(__name__)#限定类型
@app.route("/user/<int:id>")
def demo2(id):return f"hello world 这是{id}"@app.route("/user/<string:username>")
def demo3(username):return f"hello world 这是{username}同学"#启动入口
if __name__=='__main__':#flask服务启动起来#轮询等待的方式,等待浏览器发来请求#会一直接收请求,直到程序停止app.run()
4、地址尾部的“/”
路由的尾部带有“/”(浏览器的地址栏中输入和不输入“/”的效果一样)
路由的尾部没有“/”(输入的 URL 的结尾不能加“/”,会报错)
#1、导入flask模块
from flask import Flask#2、创建flask应用程序的实例;__name__ ==__main__
app=Flask(__name__)#添加路由
@app.route("/demo")
def demo():return "<p>hello world 666</p>"#启动入口
if __name__=='__main__':#flask服务启动起来#轮询等待的方式,等待浏览器发来请求#会一直接收请求,直到程序停止app.run()


三、请求与响应-请求方法
请求 说明
GET 获取服务器资源
POST 新增服务器资源
PUT 更新服务器资源(客户端提供改变后的完整资源)
DELETE 删除服务器资源
接口设计
查询:get
新增:post
修改:put
删除:delete
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/5/27 00:01
# @Author : 杜兰特
# @File : http_request_demo.py
from flask import Flaskapp=Flask(__name__)#methods是列表类型,可以添加多种请求方式。get、post、put、delete
@app.route("/cases",methods=['get'])
def get_case():return {"code":0,"msg":"get success"}@app.route("/cases",methods=['post'])
def post_case():return {"code":0,"msg":"post success"}@app.route("/cases",methods=['put'])
def put_case():return {"code":0,"msg":"put success"}@app.route("/cases",methods=['delete'])
def delete_case():return {"code":0,"msg":"delete success"}if __name__ == '__main__':app.run(debug=True)
四、请求与响应-处理请求数据
1、request的常用属性/方法
args:记录请求中的查询参数
json:记录请求中的json数据
files:记录请求上传的文件
form:记录请求中的表单数据
method:记录请求使用的http方法
url:记录请求的URL地址
host:记录请求的域名
headers:记录请求的头信息
2、get 请求参数
场景:普通的 url 链接,接收一个 get 请求
解决办法:request.args
#需要导入request,而不是requests!!!
from flask import Flask,request
from log_utils import loggerapp=Flask(__name__)@app.route('/login',methods=['get'])
def demo1():logger.info(f"请求参数为:{request.args}")a=request.args.get("a")b=request.args.get("b")logger.info(f"a的值为{a},b的值为{b}")return {"code":0,"msg":"get success"}if __name__ == '__main__':app.run(debug=True)
127.0.0.1 - - [27/May/2023 09:03:29] "GET /login HTTP/1.1" 200 -
[2023-05-27 09:04:04] [INFO] [flask_param_demo.py]/[line: 17]/[demo1] 请求参数为:ImmutableMultiDict([('a', '88'), ('b', '66')])
[2023-05-27 09:04:04] [INFO] [flask_param_demo.py]/[line: 20]/[demo1] a的值为88,b的值为66
3、json 请求
场景:POST 相关的请求,带有 json 数据格式
解决办法:request.json
#需要导入request,而不是requests!!!
from flask import Flask,request
from log_utils import loggerapp=Flask(__name__)@app.route('/register',methods=['post'])
def demo2():logger.info(f"请求参数为:{request.json}")data=request.json.get("time")logger.info(f"时间为{data}")return {"code":0,"msg":"post success"}if __name__ == '__main__':app.run(debug=True)
[2023-05-27 09:05:55] [INFO] [flask_param_demo.py]/[line: 26]/[demo2] 请求参数为:{'time': '2023-05-27', 'status': 'success'}
[2023-05-27 09:05:55] [INFO] [flask_param_demo.py]/[line: 28]/[demo2] 时间为2023-05-27
4、表单请求
场景:比如:测试人网站的登录接口,需要用户名和密码,前端会提交一个 form 表单给后台
解决办法:request.form
#需要导入request,而不是requests!!!
from flask import Flask,request
from log_utils import loggerapp=Flask(__name__)@app.route('/register',methods=['put'])
def demo3():logger.info(f"请求参数为:{request.form}")name=request.form.get("name")password=request.form.get("password")email=request.form.get("email")logger.info(f"请求参数name为:{name},password为:{password},email为;{email}")return {"code": 0, "msg": "put success"}if __name__ == '__main__':app.run(debug=True)
[2023-05-27 09:07:42] [INFO] [flask_param_demo.py]/[line: 34]/[demo3] 请求参数为:ImmutableMultiDict([('name', 'kobe'), ('password', '666666'), ('email', '77777')])
[2023-05-27 09:07:42] [INFO] [flask_param_demo.py]/[line: 38]/[demo3] 请求参数name为:kobe,password为:666666,email为;77777
5、文件请求
场景:
页面上有个更新头像的功能, 或者上传一个 excel 文件的功能, 允许我们提交一个图片,或者文件到后端服务器,那么
解决方法:
request.files.get(‘file’) 获取文件对象
filename 获取文件对象的文件名
save()方法 保存文件到指定路径下

#需要导入request,而不是requests!!!
from flask import Flask,request
from log_utils import loggerapp=Flask(__name__)@app.route('/file',methods=['post'])
def demo4():logger.info(f"请求方法为:{request.method}")logger.info(f"请求url为:{request.url}")logger.info(f"请求host为:{request.host}")logger.info(f"请求headers为:{request.headers}")fileobj=request.files.get("name")logger.info(f"fileobj的值为:{fileobj}")logger.info(f"文件名为:{fileobj.filename}")#保存文件fileobj.save(f"./{fileobj.filename}")return {"code": 0, "msg": "file success"}if __name__ == '__main__':app.run(debug=True)
[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 43]/[demo4] 请求方法为:POST
[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 44]/[demo4] 请求url为:http://127.0.0.1:5000/file
[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 45]/[demo4] 请求host为:127.0.0.1:5000
[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 46]/[demo4] 请求headers为:User-Agent: PostmanRuntime/7.32.2
Accept: */*
Postman-Token: 593d536e-4bbd-45a2-89be-d8670f66aa42
Host: 127.0.0.1:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------624583842625202752710421
Content-Length: 10016[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 48]/[demo4] fileobj的值为:<FileStorage: '员工用车导入模板 (2).xlsx' ('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')>
[2023-05-27 09:10:10] [INFO] [flask_param_demo.py]/[line: 49]/[demo4] 文件名为:员工用车导入模板 (2).xlsx
127.0.0.1 - - [27/May/2023 09:10:10] "POST /file HTTP/1.1" 200 -
五、请求与响应-处理响应信息
1、文本型
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/5/27 09:27
# @Author : 杜兰特
# @File : http_response_demo.pyfrom flask import Flask
from flask import jsonify,render_template,make_responseapp=Flask(__name__)#返回文本
@app.route("/text")
def demo():return "文本信息"if __name__ == '__main__':app.run(debug=True)
2、元组
返回元组
(response, status)
(response, headers)
(response, status, headers)
响应状态码默认为 200
from flask import Flask
from flask import jsonify,render_template,make_responseapp=Flask(__name__)#返回元组
@app.route("/tuple")
def tuple_res():return 'hello',200,{"status": 0, "type": "success"}if __name__ == '__main__':#host#port#debug=True:热加载,方便调试app.run(debug=True)

3、Json
直接返回 dict 会转换为 json
使用jsonify()方法,通过参数传入键值对
from flask import Flask
from flask import jsonify,render_template,make_responseapp=Flask(__name__)#返回字典
@app.route("/dict")
def get_dict_res():return {"status":0}@app.route("/json")
def get_json_res():#return jsonify({"status":0})#或者return jsonify(status=1,name="kobe")if __name__ == '__main__':#host#port#debug=True:热加载,方便调试app.run(debug=True)
4、html
使用模板渲染技术
html 文件必须在同级的 templates 目录下
from flask import Flask
from flask import jsonify,render_template,make_responseapp=Flask(__name__)@app.route("/html")
def get_html():return render_template("demo.html")if __name__ == '__main__':#host#port#debug=True:热加载,方便调试app.run(debug=True)
5、额外数据
设置额外数据-make_response()
添加更多的响应信息
设置 cookie
设置响应头信息等
from flask import Flask
from flask import jsonify,render_template,make_responseapp=Flask(__name__)@app.route("/")
def index():resp=make_response(render_template("demo.html"))#设置cookieresp.set_cookie("user","jimi")#设置响应头信息resp.headers["type"]="kobe"return respif __name__ == '__main__':#host#port#debug=True:热加载,方便调试app.run(debug=True)


六、测试平台环境配置
监听的主机
设置 host 参数
127.0.0.1 只能本机访问
0.0.0.0 服务发布到局域网
app.run(host="0.0.0.0")
监听的端口
设置 port 参数(默认端口号 5000)
app.run(host="0.0.0.0", port=5000)
Debug 模式
设置 debug=True(默认是 production)
实现热加载
开发调试方便
app.run(host="0.0.0.0", port=5000,debug=True)
七、接口配置
1、flask-restx 介绍
官方文档:https://github.com/python-restx/flask-restx
flask-restx 是一个支持 RESTFUL 的 flask 插件,用于规范化接口的编写,并且支持 swagger 文档。
2、插件安装
pip install flask-restx
3、demo 示例
from flask import Flask
#from flask_restful import Resource,Api
from flask_restx import Resource,Apiapp=Flask(__name__)#1、创建api实例对象
api=Api(app)#2、使用api添加路由
@api.route('/hello')
class HelloWorld(Resource): #3、类要继承Resource#4、定义restful风格的get方法def get(self):return {'hello':'world'}# restful风格的post方法def post(self):return {'post':'success'}if __name__ == '__main__':app.run(debug=True)

八、接口使用
1、设计框架的原则
复用性
高内聚,低藕合
a、高耦合实例
问题:判断条件过多,业务逻辑非常复杂
@app.route("/testcase",methods=["GET","PUT","POST"])
def select_case():### request:Requestif request.method == "GET":passelif request.method == "PUT":pass
b、低内聚示例
问题:同一个路径,对应多个请求方法,代码没有复用
# get 请求
@app.route("/testcase",methods=["get"])
def select_case():# request:Request# m = request.methodprint(dir(request))return {"code": 0, "msg":"get success"}# post 请求
@app.route("/testcase",methods=["post"])
def post_case():return {"code": 0, "msg":"post success"}# delete 请求
@app.route("/testcase",methods=["delete"])
def delete_case():return {"code": 0, "msg":"delete success"}# put 请求
@app.route("/testcase",methods=["put"])
def put_case():return {"code": 0, "msg":"put success"}
2、编写 RESTFUL 风格的接口
导入from flask_restx import Resource,Api
app=Flask(name) 创建app实例对象
api=Api(app) 创建api实例对象
使用api添加路由
类要继承Resource
定义restful风格的方法
from flask import Flask
#from flask_restful import Resource,Api
from flask_restx import Resource,Apiapp=Flask(__name__)#1、创建api实例对象
api=Api(app)#2、使用api添加路由
#@api.route('/user','/user1','/user2') 添加多个路由
@api.route('/user')
class User(Resource): #3、类要继承Resource#4、定义restful风格的get方法def get(self,id):return {"id":id,'code':0,"msg":"get success"}# restful风格的post方法def post(self):return {'code':0,"msg":"post success"}# restful风格的put方法def put(self):return {'code':0,"msg":"put success"}# restful风格的delete方法def delete(self):return {'code':0,"msg":"delete success"}api.add_resource(User,'/user/<int:id>','/user_1')if __name__ == '__main__':app.run(debug=True)
3、添加路由的方式
方式一:
添加多个路由
@api.route('/user','/user1','/user2')
@api.route('/user','/user1','/user2') 添加多个路由
@api.route('/user')
class User(Resource):
方式二
api.add_resource(User,'/user/<int:id>','/user_1')
九、集成swagger
1、namespace 的使用
定义 Namespace 实例
为类添加装饰器 @namespace.route(“”) 控制子路由
为命名空间指定访问资源路径 api.add_namespace(case_ns, ‘/case’)
from flask import Flask
from flask_restx import Api,Resource,Namespaceapp=Flask(__name__)
api=Api(app)#定义了2个命名空间
hello_ns=Namespace("demo",description="demo学习")
case_ns=Namespace("case",description="用例管理")#将api.route("case") 改为:case_ns.route("/case")
#@case_ns.route("") 定义子路由,如果没有的话,传空字符串即可
@case_ns.route("")
class TestCase(Resource):def get(self):passdef post(self):passdef put(self):passdef delete(self):pass@hello_ns.route("/demo") #子路由
class Demo(Resource):def get(self):passdef post(self):passdef put(self):passdef delete(self):passapi.add_namespace(hello_ns,"/hello")
api.add_namespace(case_ns,"/case")if __name__ == '__main__':app.run(debug=True)
2、swagger 接口文档配置
定义参数 parser = api.parser()
传递及校验参数 @api.expect(parser) 或者 @namespace.expect(parser)
a、api.parser()用法
格式:api.parser().add_argument(参数名, 关键字参数)
第一个参数是参数名
后面是关键字传参,常用的关键字有:
type :类型
required 约束控制
choices 枚举参数
location 对应 request 对象中的属性
| 参数名 | 参数值 |
|---|---|
| type | int,bool,float,string,FileStorage |
| required | True/False |
| choices | 枚举 |
| location | args,form,json,files |
b、get 请求示例
from flask import Flask, request
from flask_restx import Resource, Api, Namespace,fields
from log_utils import logger
from werkzeug.datastructures import FileStorageapp = Flask(__name__)
api = Api(app)
hello_ns = Namespace("demo", description="demo学习")@hello_ns.route("")
class Demo(Resource):#定义parser解析器对象get_parser = api.parser()#通过parser对象添加测试参数get_parser.add_argument('id',type=int,location="args",required=True)get_parser.add_argument('case_title',type=str,location="args",required=True)@hello_ns.expect(get_parser)def get(self):logger.info(f"request.args ===>{request.args}")return {"code": 0, "msg": "get success"}api.add_namespace(hello_ns,"/hello")if __name__ == '__main__':app.run(debug=True)
接口文档如下

c、post 请求示例
1、处理 json 格式
from flask import Flask, request
from flask_restx import Resource, Api, Namespace,fields
from log_utils import logger
from werkzeug.datastructures import FileStorageapp = Flask(__name__)
api = Api(app)
hello_ns = Namespace("demo", description="demo学习")@hello_ns.route("")
class Demo(Resource):post_parser=api.parser()post_parser.add_argument("id",type=int,location="json",required=True)post_parser.add_argument("casetitle",type=str,location="json",required=True)@hello_ns.expect(post_parser)def post(self):logger.info(f"request.json ===>{request.json}")return {"code": 0, "msg": "post success"}api.add_namespace(hello_ns,"/hello")if __name__ == '__main__':app.run(debug=True)

2、处理 files格式
from flask import Flask, request
from flask_restx import Resource, Api, Namespace,fields
from log_utils import logger
from werkzeug.datastructures import FileStorageapp = Flask(__name__)
api = Api(app)
hello_ns = Namespace("demo", description="demo学习")@hello_ns.route("")
class Demo(Resource):post_parser=api.parser()post_parser.add_argument("file",type=FileStorage,location="files",required=True)@hello_ns.expect(post_parser)def post(self):logger.info(f"request.files ===>{request.files}")return {"code": 0, "msg": "post success"}api.add_namespace(hello_ns,"/hello")if __name__ == '__main__':app.run(debug=True)

请求接口

3、处理 form格式
from flask import Flask, request
from flask_restx import Resource, Api, Namespace,fields
from log_utils import logger
from werkzeug.datastructures import FileStorageapp = Flask(__name__)
api = Api(app)
hello_ns = Namespace("demo", description="demo学习")@hello_ns.route("")
class Demo(Resource):post_parser=api.parser()post_parser.add_argument("param1",help="username",type=int,location="form",required=True)post_parser.add_argument("param2",help="password",type=int,location="form",required=True)@hello_ns.expect(post_parser)def post(self):logger.info(f"request.form ===>{request.form}")return {"code": 0, "msg": "post success"}api.add_namespace(hello_ns,"/hello")if __name__ == '__main__':app.run(debug=True)

[2023-05-28 22:04:04] [INFO] [swagger_demo2.py]/[line: 53]/[post] request.form ===>ImmutableMultiDict([('param1', '24'), ('param2', '123567')])
127.0.0.1 - - [28/May/2023 22:04:04] "POST /hello HTTP/1.1" 200 -
4、处理choice格式
from flask import Flask, request
from flask_restx import Resource, Api, Namespace,fields
from log_utils import logger
from werkzeug.datastructures import FileStorageapp = Flask(__name__)
api = Api(app)
hello_ns = Namespace("demo", description="demo学习")@hello_ns.route("")
class Demo(Resource):post_parser=api.parser()post_parser.add_argument("choice", location="args", required=True,choices=(1,2,3,4))@hello_ns.expect(post_parser)def post(self):logger.info(f"request.args ===>{request.args}")return {"code": 0, "msg": "post success"}api.add_namespace(hello_ns,"/hello")if __name__ == '__main__':app.run(debug=True)
[2023-05-28 22:06:14] [INFO] [swagger_demo2.py]/[line: 54]/[post] request.args ===>ImmutableMultiDict([('choice', '2')])
127.0.0.1 - - [28/May/2023 22:06:14] "POST /hello?choice=2 HTTP/1.1" 200 -
十、orm介绍
1、什么是持久化
持久化(Persistence) 即把数据保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中。当然也可以存储在磁盘文件中、XML数据文件中等等。
2、什么是 ORM
Object Relational Mapping 对象关系映射
作用是在关系型数据库和对象之间做一个映射,这样在具体操作数据库的时候,就不需要再去和复杂的 SQL 语句打交道,只要像平时操作对象一样操作就可以了

3、ORM 与 SQL 的对比
# 使用sql语句查询数据
sql = "SELECT
username, email, gender
FROM User WHERE id = 1"# 执行sql 代码
res = db.execSql(sql);# 取出数据
name = res[0]
# 使用orm 查询数据,定义ORM对象,get 值 ,
res = db.session.query(\User.username, User.email, User.gender).\filter(User.id==1).first()
name = res.username

4、ORM 优缺点
优势:
隐藏了数据访问细节
ORM 使我们构造固化数据结构变得非常简单
缺点:
性能下降 ,添加了关联操作,性能不可避免的会下降一些
无法解决特别复杂的数据库操作
十一、orm中间件配置
from flask import Flask
# 实例化 Flask的类,并且绑定module
from flask_sqlalchemy import SQLAlchemy
# 实例化 Flask
app=Flask(__name__)
# mysql 数据库用户名
username="root"
# mysql 数据库密码
pwd="root"
# mysql 数据库的 host 地址
ip="127.0.0.1"
# mysql 数据库端口
port="3306"
# 代码使用的数据库名
datebase="demo"
# 设置mysql 链接方法是
app.config['SQLALCHEMY_DATABASE_URL']=f"mysql+pymysql://{username}:{pwd}@{ip}:{port}/{database}?charset=utf-8"
# 定义应用使用数据库的配置
# 设置SQLALCHEMY_TRACK_MODIFICATIONS参数 不设置该配置的时候会抛出警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True
# 将 app 与 Flask-SQLAlchemy 的 db 进行绑定
db=SQLAlchemy(app)
十二、数据库与表管理
Flask-SQLAlchemy 数据库连接的配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://username:password@host:port/database'
database:username: rootpassword: rootserver: 127.0.0.1:3306db: flask_1
定义数据库的表 需要继承 db.Model,db 为 app 启动的时的 SQLAlchemy 绑定的实例
类名,相当于表名
驼峰命名的类名,转为下划线连接。例如 class UserInfo 建立的表名为 user_info
自定义表名,__tablename__= 自定义的表名
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/5/28 22:37
# @Author : 杜兰特
# @File : sqlachemy_demo.pyfrom flask import Flask
from flask_sqlalchemy import SQLAlchemy
# 实例化app 对象
from sqlalchemy import *
import yamlapp = Flask(__name__)
with open("./data.yaml") as f :result = yaml.safe_load(f)username = result.get("database").get('username')password = result.get("database").get('password')server = result.get("database").get('server')db = result.get("database").get('db')
app.config['SQLALCHEMY_DATABASE_URI'] = \f"mysql+pymysql://{username}:{password}@{server}/{db}?charset=utf8"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# SQLAlchemy 绑定app
db = SQLAlchemy(app)# 定义数据库的表 需要继承 db.Model,db 为 app 启动的时的 SQLAlchemy 绑定的实例# 类名,相当于表名
#驼峰命名的类名,转为下划线连接。例如 class UserInfo 建立的表名为 user_info
#自定义表名,__tablename__= 自定义的表名
class User(db.Model):__tablename__="User" #指定表名id = Column(Integer, primary_key=True)username = Column(String(80))class StudentInfo(db.Model):id = Column(Integer, primary_key=True)username = Column(String(80))if __name__ == '__main__' :#可以创建多个表db.create_all()#db.drop_all()
创建表操作
可以创建多个表
db.create_all()
删除表操作
db.drop_all()
十三、对象与数据模型
1、数据模型
数据模型(Data Model)是数据特征的抽象,它从抽象层次上描述了系统的静态特征、动态行为和约束条件,为数据库系统的信息表示与操作提供一个抽象的框架。
2、设计用户表字段

3、Flask-SQLAlchemy 的属性字段定义
通常类的属性相当于表的一个字段
定义的属性的方式为 name=Column(参数的类型, 其他的属性)
官方:https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/?highlight=column
| 参数类型 | 含义 |
|---|---|
| Integer | 整型字段定义 |
| String(20) | 字符串字段定义,括号为字符串的最大长度 |
| JSON | json 字符串字段 |
| DateTime | 时间格式字段 |
4、Flask-SQLAlchemy 字段常用关键字参数
| 参数类型 | 含义 |
|---|---|
| primary_key | 是否主键 |
| autoincrement | 是否自增 |
| nullable | 是否允许为空 |
| unique | 是否允许重复 |
| default | 默认值 |
5、Flask-SQLAlchemy 对象与数据模型示例
每一个类变量表示一个数据库表的列名
第一个参数是表示数据的类型, primary_key=True 表示是主键
unique = True 表示是不能重复的
nullable=False 表示不可以为空
from sqlalchemy import *
from flask_sqlalchemy import SQLAlchemy
import yaml
# 导入 Query 以便于调用的时候代码提示
from sqlalchemy.orm import Query
from flask import Flask
app = Flask(__name__)with open("./data.yaml") as f :result = yaml.safe_load(f)username = result.get("database").get('username')password = result.get("database").get('password')server = result.get("database").get('server')db = result.get("database").get('db')
app.config['SQLALCHEMY_DATABASE_URI'] = \f"mysql+pymysql://{username}:{password}@{server}/{db}?charset=utf8"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# SQLAlchemy 绑定app
db = SQLAlchemy(app)# 定义数据库的表 需要继承 db.Model
class User(db.Model):__tablename__ = "user" # 设置数据库表名# 每一个类变量表示一个数据库表的列名# 第一个参数是表示数据的类型, primary_key=True 表示是主键id = Column(Integer, primary_key=True)# unique = True 表示是不能重复的 nullable=False 表示不可以为空username = Column(String(80), unique=False, nullable=False)email = Column(String(120), unique=True, nullable=False)gender = Column(String(3),unique=False)def __repr__(self):# 数据库的 魔法方法 直观展示数据'''[<User "张三">,<User "李四">]'''return f'<User {self.username}>'
十四、数据CRUD
1、添加数据(create)
a、单条数据新增
实例化类,创建表数据
将实例添加到 session(add)
提交更新 (commit)
关闭 session
# 新增表数据,需要导入 User 类,进行实例化
user=User(id=1,username="kobe",email="111@qq.com",gender="男")
print(user)
db.session.add(user)
db.session.commit()
db.session.close()
b、多条数据新增
多次实例化类,创建多条表数据
将多个实例依次添加到 session 中(add)或者一次性添加到 session 中(add_all)
提交更新 (commit)
关闭 session
# 批量添加数据操作
user1 = User(username="kobe1", email="1113@qq.com", gender="男")
user2 = User(username="kobe2", email="1114@qq.com", gender="女")
db.session.add_all([user1,user2])
db.session.commit()
db.session.close()
2、读取数据(read)
a、查询表中全部数据
格式:类.query.all()
# 读取全部数据
res = User.query.all()
# 遍历数据,得到想要的字段
for rs in res:print(rs.username, rs.email)
b、条件查询——单条件查询
格式:类.query.filter_by(条件).单条或多条
查询单条数据:类.query.filter_by(条件).first()
res=User.query.filter_by(gender='男').first()
print(res)
查询多条数据:类.query.filter_by(条件).all()
res_list=User.query.filter_by(gender="男").all()
print(res_list)
c、条件查询——多条件查询
查询单条数据:类.query.filter_by(条件).filter_by(条件)…first()
res1=User.query.filter_by(gender="男").filter_by(username="kobe1").first()
print(res1)
查询多条数据:类.query.filter_by(条件).filter_by(条件)…all()
res2 = User.query.filter_by(gender="男").filter_by(username="kobe1").all()
print(res2)
3、修改数据(update)
方式一:
首先查询出来需要的数据
对查询出来的数据对象进行属性的修改
提交 session
user3=User.query.filter_by(id=2).first()
user3.gender="女"
db.session.commit()
db.session.close()
方式二:
给定查询条件进行查询后,直接进行 update 操作
提交 session
res4=User.query.filter_by(id=3).update({"username":"butler"})
db.session.commit()
db.session.close()
4、删除数据(delete)
方式一:
查询数据
对查询出来的数据对象进行删除操作
提交 session
user5=User.query.filter_by(id=1).first()
db.session.delete(user5)
db.session.commit()
db.session.close()
方式二:
给定查询条件进行查询后,直接进行 delete 操作
提交 session
user5=User.query.filter_by(id=2).delete()
db.session.commit()
db.session.close()
十五、多表关系-一对多
1、一对多关系
场景:
一个班级有多个学生
一个学生只在一个班级
一对多关系中,通过外键来关联数据,外键设置在多的一方
SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到了。另外,可以通过backref来指定反向访问的属性名称。
特别注意:
classinfo=db.relationship(‘ClassInfo’,backref=“studentinfo”):代表学生所属的班级信息,backref:反向关联的属性名,classinfo=db.relationship(‘ClassInfo’,backref=“studentinfo”):中的ClassInfo必须是另外一个相关联的类名
from sqlalchemy import *
from flask_sqlalchemy import SQLAlchemy
import yaml
# 导入 Query 以便于调用的时候代码提示
from sqlalchemy.orm import Query
from flask import Flask
app = Flask(__name__)with open("../data.yaml") as f :result = yaml.safe_load(f)username = result.get("database").get('username')password = result.get("database").get('password')server = result.get("database").get('server')db = result.get("database").get('db')
app.config['SQLALCHEMY_DATABASE_URI'] = \f"mysql+pymysql://{username}:{password}@{server}/{db}?charset=utf8"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# SQLAlchemy 绑定app
db = SQLAlchemy(app)# 班级表
class ClassInfo(db.Model):__tablename__ = "Class"id = Column(Integer, primary_key=True)name = Column(String(80))def __repr__(self):return f"<Class:{self.name}>"# 学生表
class StudentInfo(db.Model):# 指定表名__tablename__属性__tablename__ = "Student"id = Column(Integer, primary_key=True)name = Column(String(80))#添加外键classid = Column(Integer, ForeignKey("Class.id"))# 第一个参数:表示这个关系的另一端是 ClassInfo 类。比如班级id=1# 第二个参数:backref, 表示反向引用,需要从班级id为1 反向获取【多】的时候,使用的属性# 通过ClassInfo实例.studentinfoclassinfo=db.relationship('ClassInfo',backref="studentinfo")def __repr__(self):return f"<Student:{self.name}>"
2、一对多表结构
创建表
db.create_all()
删除表
db.drop_all()
3、一对多增删查改
a、数据新增
Class 班级表:添加两条数据
class1 = ClassInfo(id=1, name="测开21期")
class2 = ClassInfo(id=2, name="测开22期")
db.session.add_all([class1, class2])
db.session.commit()
db.session.close()
要先完全创建好,数据库中的班级表,再去创建学生表
Student 学生表:添加两条数据
student1 = StudentInfo(id=1, name="学生一", classid=1)
student2 = StudentInfo(id=2, name="学生二", classid=1)
student3 = StudentInfo(id=3, name="学生三", classid=2)
student4 = StudentInfo(id=4, name="学生四", classid=2)
db.session.add_all([student1, student2,student3, student4])
db.session.commit()
db.session.close()
b、数据查询
多查一
通过学生id=1 查询学生所在的班级
stu1=StudentInfo.query.filter_by(id=1).first()
#获取classid信息
print(stu1.classid)
print(stu1.classinfo)
print(stu1.classinfo.name)
一查多
通过班级id=1,查询对应的学生
class1=ClassInfo.query.filter_by(id=1).first()
print(class1.studentinfo)
print(class1.studentinfo[0].name)
c、数据修改
一改多
通过班级修改学生信息
class1=ClassInfo.query.filter_by(id=1).first()
print(class1.studentinfo)
class1.studentinfo[0].name="学生修改1"
db.session.commit()
db.session.close()
多改一
通过学生修改班级信息
stu2=StudentInfo.query.filter_by(id=2).first()
print(stu2.classinfo)
stu2.classinfo.name="pythonvip"
db.session.commit()
db.session.close()
d、数据删除
删除一个班级下的所有学生
class1=ClassInfo.query.filter_by(id=1).first()
StudentInfo.query.filter(StudentInfo.classid==class1.id).delete()
db.session.commit()
db.session.close()
相关文章:
Flask——接口路由技术
接口路由技术 一、Flask 简介1、环境安装:2、一个最小的应用3、两种运行方式 二、定义路由1、普通路由2、动态路由3、限定类型4、地址尾部的“/” 三、请求与响应-请求方法四、请求与响应-处理请求数据1、request的常用属性/方法2、get 请求参数3、json 请求4、表单…...
Dubbo篇---第一篇
系列文章目录 文章目录 系列文章目录一、说说一次 Dubbo 服务请求流程?二、说说 Dubbo 工作原理三、Dubbo 支持哪些协议?一、说说一次 Dubbo 服务请求流程? 基本工作流程: 上图中角色说明: 二、说说 Dubbo 工作原理 工作原理分 10 层: 第一层:service 层,接口层,…...
powermock-成员变量赋值
powermock成员变量设置 //被测试类 Service public class Demo {private String aaa ;public String method1(){return aaa;} }//测试类,测试类中使用了mockito、和powermock,用powermock设置成员变量相较于mockito简洁一些,一般mockito和po…...
Axios请求成功和失败时分别执行哪个函数?
在 Axios 中,请求成功和失败时分别执行的函数是 then 和 catch。 特点: then 函数用于处理请求成功的情况,它接受一个回调函数作为参数,在请求成功时会调用该回调函数。catch 函数用于处理请求失败的情况,它也接受一…...
【Linux】进程概念III --fork函数解析
Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法…感兴趣就关注我吧!你定不会失望。 本篇导航 0. 创建进程1. 认识fork函数2.使用Fork函数3.关于fork的为什么3.1 一个函数如何返回两次?fork究竟在干什么?3.2 为什么要给子…...
关闭 Android SplashScreen(闪屏)
SplashScreen在Android 12上是强制的,如果你什么都不做,你的App在Android 12上就会自动拥有SplashScreen界面 但是这个SplashScreen界面太局限了能改的地方太少了 其实也没什么他主要作用是为了在App启动初始化的时候避免让用户在一个空白界面等待过长时…...
react_16
主页 import {DownCircleOutlined,MenuFoldOutlined,VerticalAlignTopOutlined, } from "ant-design/icons"; import { Button, Layout, Menu } from "antd"; import { ItemType } from "antd/es/menu/hooks/useItems"; import { Link, Navigat…...
前端性能分析工具
前段时间在工作中,需要判断模块bundle size缩减对页面的哪些性能产生了影响, 因此需要了解前端的性能指标如何定义的,以及前端有哪些性能分析工具, 于是顺便整理了一篇笔记, 以供前端小白对性能这块知识点做一个入门级的了解. 页面渲染 在了解性能指标和分析工具之前,有必要先…...
根据Aurora发送时序,造Aurora 数据包,从而进行AXIS接口数据位宽转换仿真
首先Aurora采用AXIS接口 由于后续需要进行AXIS接口 不同时钟域的数据位宽转换(64bit和256bit之间的转换),因此分两次走。 第一种方法:采用AXIS数据位宽转换IP AXIS跨时钟域IP 第二种方法:逻辑完成 下面记录逻辑…...
java后端响应结果Result
目录 一、Result1-1、响应代码1-2、调用响应1-3、在前端vue页面使用方法 一、Result 1-1、响应代码 package com.aaa.common;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public cla…...
react_11
MobX 介绍 需求,组件0 改变了数据,其它组件也想获得改变后的数据,如图所示 这种多个组件之间要共享状态数据,useState 就不够用了,useContext 也不好用了 能够和 react 配合使用的状态管理库有 MobX Redux 其中…...
AI:52-基于深度学习的垃圾分类
🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…...
[shell,hive] 在shell脚本中将hiveSQL分离出去
将Hive SQL语句写在单独的.hql文件中, 然后在shell脚本中调用这些文件来执行Hive查询。 这样可以将SQL语句与shell脚本分离,使代码更加清晰和易于维护。 基本用法 以下是一个示例,展示如何在shell脚本中使用.hql文件执行Hive查询…...
求两个(法)向量之间的rpy夹角
主要使用Eigen库实现: 1. 四元素到欧拉角的转换 #include <array> #include <Eigen/Geometry>template <typename T> inline Eigen::Matrix<typename std::remove_reference<T>::type::Scalar, 3, 1> eulerAnglesZYX(T q_in) {typedef typenam…...
[100天算法】-每个元音包含偶数次的最长子字符串(day 53)
题目描述 给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 a,e,i,o,u ,在子字符串中都恰好出现了偶数次。示例 1:输入:s &qu…...
从科幻走向现实,LLM Agent 做到哪一步了?
LLM 洪流滚滚,AI 浪潮席卷全球,在这不断冲击行业认知的一年中,Agent 以冉冉新星之态引起开发者侧目。OpenAI 科学家 Andrej Karpathy 曾言“OpenAI 在大模型领域快人一步,但在 Agent 领域,却是和大家处在同一起跑线上。…...
[笔记] 数据类型
整形 一字节(Byte,也就是平时KB、MB里面的B)就是八个二进制位(bit) 整形——int——4B无符号整形——unsigned int——4B短整形——short——2B长整型——long——4B双长整型——long long——8B 浮点型 参考博客:C 语言的浮点类型…...
QT学习之QT概述
1.1 什么是QT? Qt是一个跨平台的C图形用户界面应用程序框架。 QT特点: 跨平台,几乎支持所有的平台接口简单,容易上手,学习QT框架对学习其他框架有参考意义。一定程度上简化了内存回收机制开发效率高,能够…...
编写shell脚本,利用mysqldump实现MySQL数据库分库分表备份
查看数据和数据表 mysql -uroot -p123456 -e show databases mysql -uroot -p123456 -e show tables from cb_d 删除头部Database和数据库自带的表 mysql -uroot -p123456 -e show databases -N | egrep -v "information_schema|mysql|performance_schema|sys"编写…...
本地部署Jellyfin影音服务器并实现远程访问影音库
文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
