FLASK的一些查询操作和项目基本流程
API设计
-
所有班级
GET cls/- flask
- 根据班级模型类查询全部数据
- 先排序(
desc(字段)) - 再分页
- 最后序列化解析
- 返回解析后的数据,格式:
[{},{}]
- Vue
- 定义方法,使用axios的 GET请求所有班级数据
- 挂载方法
- 循环展示
- flask
-
所有学生
GET stu/-
flask
- 根据学生模型类查询全部数据
- 先排序(
desc(字段)) - 再分页
- 最后序列化解析
- 返回解析后的数据,格式:
[{},{}]
-
Vue
- 定义方法,使用axios的 GET请求所有班级数据
- 挂载方法
- 循环展示
-
-
班级的学生
GET cls/stu/?cls_id=xx- flask
- 接收参数: 班级id
- 在 学生模型类 中查询: 使用
filter_by, 过滤班级的学生 - 序列化解析
- 直接返回数据
- Vue
- 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串:
cls_id - 挂载方法
- 循环展示
- 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串:
- flask
-
搜索
GET stu/search/?text=xx- flask
- 接收参数:关键字
- 在 学生模型类 中查询: 使用
filter(), 条件既可以是 班级名 ,也可以是 学生名 - 序列化解析
- 直接返回数据
- Vue
- 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串:
text - 挂载方法
- 循环展示
- 定义方法,使用axios的 GET请求所有班级数据, 需要传递 查询字符串:
- flask
Flask
项目构建
app包
负责 生成
flask项目的核心app
config.py
指定 项目的app所需的 配置项
class Config(object):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@localhost:3306/flask07'
SQLALCHEMY_TRACK_MODIFICATIONS = False
extensions.py
指明 项目所使用的的 第三方 插件
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_cors import CORS
# 如果安装的插件是pymysql,还需要另外两句话
db = SQLAlchemy() # 链接数据库
migrate = Migrate() # 迁移模型类
cors = CORS() # 跨域
def config_extensions(app):
db.init_app(app)
migrate.init_app(app, db=db)
cors.init_app(app)
__init__.py
创建工厂函数,导入配置项、第三方插件、(蓝图),最后返回 app
from flask import Flask
from .config import Config
from .extensions import config_extensions
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
config_extensions(app)
# 后期创建完蓝图之后,需要注册蓝图
return app
manage.py
负责管理项目: 迁移模型类、启动服务
from flask_script import Manager, Server
from flask_migrate import MigrateCommand
from app import create_app
# 1. 利用工厂函数生成APP
app = create_app()
# 2. 创建manage 管理app的对象
manage = Manager(app)
# 3. 给管理对象中添加命令
manage.add_command('runserver', Server())
manage.add_command('db', MigrateCommand)
if __name__ == '__main__':
manage.run()
蓝图
蓝图类似于django中的子应用,一般是每个功能模块 创建一个 蓝图
__init__.py
创建蓝图,注册蓝图
from flask import blueprints
school_bp = blueprints.Blueprint('school', __name__)
在
app/__init__.py中的 工厂函数中国注册蓝图
app.register_blueprint(school_bp)
models.py
当前功能模块的所有模型类
from app.extensions import db
from datetime import datetime
class Cls(db.Model):
__tablename__ = 'tb_cls'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(32), nullable=False, unique=True)
state = db.Column(db.Integer, default=1)
addtime = db.Column(db.DATETIME, default=datetime.now)
class Stu(db.Model):
__tablename__ = 'tb_stu'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(32), nullable=False, unique=True)
age = db.Column(db.Integer)
gender = db.Column(db.Integer, default=1)
state = db.Column(db.Integer, default=1)
addtime = db.Column(db.DATETIME, default=datetime.now)
# 外键字段
cls_id = db.Column(db.Integer, db.ForeignKey('tb_cls.id'))
# 外键关系
cls = db.relationship('Cls', backref='students')
需要让 蓝图识别 模型类,需要在
__init__.py中导入模型类
from .models import *
在终端使用如下命令,生成表
python manage.py db init #初始化,生成迁移目录
python manage.py db migrate # 根据模型类,生成迁移文件
python manage.py db upgrade # 根据迁移文件,生成表
views.py
一般 定义 视图类,进行业务逻辑处理,返回数据
班级列表页
GET cls/
为了提高查询速度,再重新每个班级时,顺便 提高 反向查询,得到每个班级的学生,在前端Vue再判断展示
from flask_restful import Resource, reqparse
from sqlalchemy import desc
from .models import *
class ClsView(Resource):
def get(self):
# 1. 创建解析参数的对象
parser = reqparse.RequestParser()
# 2. 指明需要解析的参数
parser.add_argument('page', type=int, location='args', default=1, help='页码不合法')
# 3. 获取参数, 得到 字典 { 参数名: 参数值}
args = parser.parse_args()
# 4. 从字典中取出具体的 参数
page = args.get('page')
# 5. 先查询,后排序,再分页, 得到分页器对象
pagination = Cls.query.order_by(desc('addtime')).paginate(page=page, per_page=2)
# 6. 为了解析时间格式,还是 手动解析
cls = [
{
'id': cls.id,
'name': cls.name,
'state': cls.state,
'add_time': cls.addtime.strftime('%Y-%m-%d %H:%M:%S'),
'stus': [
{
'id': stu.id,
'name': stu.name,
'gender': '男' if stu.gender else '女',
'age': stu.age,
'state': stu.state,
}
for stu in cls.students
]
}
for cls in pagination.items
]
# 7. 返回响应数据
return {
'cls': cls,
'pages': pagination.pages
}
学生列表页
from flask_restful import Resource, reqparse
from sqlalchemy import desc
from .models import *
class StuView(Resource):
def get(self):
# 1. 创建解析参数的对象
parser = reqparse.RequestParser()
# 2. 指明需要解析的参数
parser.add_argument('page', type=int, location='args', default=1, help='页码不合法')
# 3. 获取参数, 得到 字典 { 参数名: 参数值}
args = parser.parse_args()
# 4. 从字典中取出具体的 参数
page = args.get('page')
# 5. 先查询,后排序,再分页, 得到分页器对象
pagination = Stu.query.order_by(desc('addtime')).paginate(page=page, per_page=2)
# 6. 为了解析时间格式,还是 手动解析
stus = [
{
'id': stu.id,
'name': stu.name,
'gender': '男' if stu.gender else '女',
'age': stu.age,
'state': stu.state,
'cls': stu.cls.name,
'add_time': stu.addtime.strftime('%Y-%m-%d %H:%M:%S')
}
for stu in pagination.items
]
# 7. 返回响应数据
return {
'stus': stus,
'pages': pagination.pages
}
模糊查询
flask想要查询 关联表的字段,不能直接查询,需要先将 两表进行连接, 再查询字段
class SearchView(Resource):
def get(self):
# 1. 创建解析参数的对象
parser = reqparse.RequestParser()
# 2. 指明需要解析的参数
parser.add_argument('text', type=str, location='args', help='关键字不合法')
# 3. 获取参数, 得到 字典 { 参数名: 参数值}
args = parser.parse_args()
# 4. 从字典中取出具体的 参数
text = args.get('text')
# 5. 根据关键字模糊查询, 得到学生的 查询集
stus = Stu.query.join(Cls, Cls.id == Stu.cls_id). \
filter(or_(
Cls.name.like('%{}%'.format(text)),
Stu.name.like('%{}%'.format(text))
)).all()
# 6. 循环解析
data = [
{
'id': stu.id,
'name': stu.name,
'gender': '男' if stu.gender else '女',
'age': stu.age,
'state': stu.state,
'cls': stu.cls.name,
'add_time': stu.addtime.strftime('%Y-%m-%d %H:%M:%S')
}
for stu in stus
]
return {
'stus': data
}
路由配置
一般是 蓝图的
__init__.py中添加路由
from flask import blueprints
from flask_restful import Api
from .models import *
from .views import *
school_bp = blueprints.Blueprint('school', __name__)
api = Api(school_bp) # 创建路由对象
api.add_resource(ClsView, '/cls')
api.add_resource(StuView, '/stu')
Vue
在Vue项目中,有某个功能经常使用,可以单独定义一个组件,后期 复用即可
封装组件
<template>
<div>
<button>
<routerLink :to="{name:'Cls'}" :style="{'text-decoration': 'none'}">
所有班级
</routerLink>
</button>
<button>
<routerLink :to="{name:'Stu'}" :style="{'text-decoration': 'none'}">所有学生</routerLink>
</button>
</div>
</template>
<script>
export default {
name: "navbar"
}
</script>
班级列表页
<template>
<div>
<navbar></navbar>
<h1>班级列表</h1>
<!-- 3 先循环班级列表,在每个班级展示时,循环对应的学生列表, 默认不显示,点击查看按钮,修改状态 -->
<div v-for="(c, index) in cls" :key="index">
<p>
{{ c.id }} == {{ c.name }} == {{ c.add_time }} == {{ c.state }}
<button @click="c.flag = !c.flag">查看</button>
</p>
<div v-for="s in c.stus" v-if="c.flag">
{{ s.id }} == {{ s.name }} == {{ s.age }} == {{ s.gender }}
</div>
</div>
<!-- 4 循环所有页码,生成页码按钮 -->
<button @click="pageChange(page-1)">上一页</button>
<button v-for="i in pages" @click="pageChange(i)">{{ i }}</button>
<button @click="pageChange(page+1)">下一页</button>
</div>
</template>
<script>
import navbar from "./navbar";
export default {
name: "Cls",
components: {
navbar
},
data() {
return {
// 0. 对应空数据
cls: [], // 当前页的所有数据
pages: 1, // 总页码
page: 1, // 当前页
}
},
methods: {
// 1. 定义方法,请求当前页的数据,传递 页码
get_cls() {
this.$axios.get('/cls', {
params: {
'page': this.page
}
})
.then(resp => {
this.cls = resp.data.cls
this.pages = resp.data.pages
})
},
// 5, 点击页码按钮,传递当前按钮代表 的 页码
pageChange(n) {
// 5.1 判断传递的 数字n 是否符合页码规则
if (n < 1 || n > this.pages || this.page === n) {
return
}
// 5.2 根据新的数字n修改 当前页码page
this.page = n
// 5.3 根据新页码,重新请求班级数据
this.get_cls()
}
},
mounted() {
// 2. 挂载执行请求数据的方法
this.get_cls();
}
}
</script>
学生列表页
<template>
<div>
<navbar></navbar>
<h1>学生列表</h1>
<!-- 3 只需要循环学生列表即可 -->
<div v-for="(s, index) in stu" :key="index">
{{ s.id }} == {{ s.name }} == {{ s.age }} == {{ s.gender }} == {{ s.add_time }} == {{ s.cls }}
</div>
<!-- 4 循环所有页码,生成页码按钮 -->
<button @click="pageChange(page-1)">上一页</button>
<button v-for="i in pages" @click="pageChange(i)">{{ i }}</button>
<button @click="pageChange(page+1)">下一页</button>
</div>
</template>
<script>
import navbar from "./navbar";
export default {
name: "Stu",
components: {
navbar
},
data() {
return {
// 0. 对应空数据
stu: [], // 当前页的所有数据
pages: 1, // 总页码
page: 1, // 当前页
}
},
methods: {
// 1. 定义方法,请求当前页的数据,传递 页码
get_stus() {
this.$axios.get('/stu', {
params: {
'page': this.page
}
})
.then(resp => {
this.stu = resp.data.stus
this.pages = resp.data.pages
})
},
// 5, 点击页码按钮,传递当前按钮代表 的 页码
pageChange(n) {
// 5.1 判断传递的 数字n 是否符合页码规则
if (n < 1 || n > this.pages || this.page === n) {
return
}
// 5.2 根据新的数字n修改 当前页码page
this.page = n
// 5.3 根据新页码,重新请求班级数据
this.get_stus()
}
},
mounted() {
// 2. 挂载执行请求数据的方法
this.get_stus();
}
}
</script>
搜索页面
v-model获取用户输入的 关键字- 点击搜索按钮,执行搜索方法
- 在方法中,发送 get请求, 携带 关键字参数
- 请求成功,在页面循环展示所有数据

浙公网安备 33010602011771号