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. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...

【数据结构】希尔排序
文章目录 前言一、希尔排序的演示图例二、希尔排序:插入排序的优化版本☆三、核心算法思路四、算法思路步骤(一)预排序 gap>1(二)gap1 插入排序 完成排序收尾 五、码源详解(1)ShellSort1 ——…...

使用VBA打印PDF文件
使用VBA打印工作表和工作簿文件都很容易实现,但是有时需要使用VBA打印已经保存在本机的其他文件,例如PDF文件格式的账单,如果这个PDF并非由Excel生成的那么就无法使用前述方法实现。 调用Windows的Shell命令可以实现打印PDF文件。 示例代码…...

分布式ID系统设计(2)
接上文 https://editor.csdn.net/md/?articleId=133988963 类snowFlake 方案 应用举例 mongoDB ObjectID 就是一个典型的实现。数据库生成 以MySQL举例 利用给字段设置AUTO-INCREMENT来保证ID自增,每次业务使用SQL拿到MySQL的ID 这种方案的优缺点: 优点 1 简单。利用数据库实…...

http和https的区别,以及https涉及到的加密过程
一.http与https的介绍 http:超文本传输协议,是互联网应用最广泛的一种网络协议。设计的最初目的是为了提供一种发布和接收HTML页面的方法。是以明文的形式来传输的,所以就会存在一定的安全隐患(因为攻击者可以截取web服务器和网站相关的报文…...

使用php打印时间精确到毫秒及毫秒转成11位时间戳
在PHP中,可以使用microtime函数来获取当前时间,包括毫秒。以下是示例代码: // 获取当前时间戳(秒) $time microtime(true); // 将当前时间戳转换为毫秒 $milliseconds round($time * 1000); // 输出当前时间&#…...

uni-app离线打包在android studio创建的.jks证书,签名文件获取MD5问题
获取证书信息 keytool -list -v -keystore test.keystore 获取的信息中没有md5信息 可以使用以下方式获取md5. 先创建签名文件,放到项目目录下 配置build.gradle文件 在android studio 打开终端输入以下命令 ./gradlew signingReport 等待生成签名。 生成的内容…...

333333333333
一、Map 接口 接下来讲的都是基于 jdk8 来开展的。 1.1 特点 1、Map 与 Collection 并列存在。Map 是用于保存具有映射关系的数据,即 key-value。 2、Map 中的 key 和 value 可以是任何引用类型的数据类型。 3、Map 中的 key 不允许重复,原因和 HashSet…...

Python:字符串格式化
文章目录 %用法使用format方法进行格式化 %用法 格式字符说明%s字符串%c单个字符%d十进制整数%o八进制整数%x十六进制整数%e指数(基底写为e)%E指数(基底写为E) x 1235 print(%o % x) print(%d % x) print(%x % x) print(%e % x) print(%s % 65) print(%c % a)使用format方法…...

虹科示波器 | 汽车免拆检修 | 2010款江铃陆风X8车发动机怠速抖动、加速无力
一、故障现象 一辆2010款江铃陆风X8车,搭载4G6GS4N发动机,累计行驶里程约为20万km。该车在其他修理厂进行发动机大修,维修后试车,发动机怠速抖动、加速无力。用故障检测仪检测,发动机控制模块(ECMÿ…...