flask + layui 实现学员信息案例
接下来演示用 flask + layui 搭建一个学员信息管理的案例
这个案例将会利用 flask 做后端,layui table 组件做前端,基于 restful api 完成一个学员信息管理的完整案例。 案例内容涉及的知识点会比较多,但是对于基础,我在案例中也不会过多赘述,当看不懂时可以查阅一下官方文档或者补一下对应的基础知识。
项目搭建
- 新建 flask 项目
- 下载 layui 文件,解压之后复制到指定文件
- 配置 flask-sqlalchemy 插件
- 完成数据库建模,数据表创建
创建项目
创建项目的方式有很多种,只要有任意一种方式创建即刻。在这里我直接选择使用 pycharm 进行创建。
创建成功后目录如下
X:\flask-student>tree /f
X:.
│ app.py
│
├─static
└─templates
访问 https://layui.dev/ ,点击直接下载之后就能得到 layui 的静态文件,将其复制到 static 目录下,完成之后的目录结构如下
X:\flask-student>tree /f
X:.
│ app.py
│
├─static
│ │ layui.js
│ │
│ ├─css
│ │ layui.css
│ │
│ └─font
│ iconfont.eot
│ iconfont.svg
│ iconfont.ttf
│ iconfont.woff
│ iconfont.woff2
│
└─templates
配置插件
1、安装插件
pip install flask-sqlalchemy
2、添加配置文件
# 数据库链接配置
SQLALCHEMY_DATABASE_URI = 'sqlite:///flask-student.sqlite'
SQLALCHEMY_TRACK_MODIFICATIONS = False
3、创建实例对象
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def register_extension(app):
db.init_app(app)
4、绑定到 flask app
import config
from extensions import register_extension, db
app.config.from_object(config)
register_extension(app)
数据库建模
1、创建数据模型
from extensions import db
from datetime import datetime
class StudentORM(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
gender = db.Column(db.Enum('M', 'F'))
mobile = db.Column(db.String(11), nullable=False, unique=True)
class_name = db.Column(db.String(10), nullable=True)
address = db.Column(db.String(255))
disable = db.Column(db.Boolean, default=False)
is_del = db.Column(db.Boolean, default=False)
create_at = db.Column(db.DateTime, default=datetime.now) # 记录的创建时间
update_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) # 记录的更新时间
def save(self):
db.session.add(self)
db.session.commit()
2、生成数据表
from orms import StudentORM
@app.cli.command()
def create():
db.drop_all()
db.create_all()
from faker import Faker
import random
faker = Faker(locale="zh-CN")
for i in range(100):
student = orms.StudentORM()
info = faker.simple_profile()
student.name = info['name']
student.gender = info['sex']
student.mobile = faker.phone_number()
student.address = info['address']
student.class_name = random.choice(['一班', '二班', '三班'])
student.save()
学员信息渲染
需要完成的工作如下:
- 返回学员信息页面,在前端请求后端接口数据
- 返回学员信息接口,并且支持分页、查询(后续待用)
后端部分
1、编写后端接口返回前端数据,返回数据
@app.route('/api/student')
def student_view():
page = request.args.get('page', type=int, default=1)
per_page = request.args.get('per_page', type=int, default=10)
paginate = StudentORM.query.paginate(page=page, per_page=per_page, error_out=False)
items: [StudentORM] = paginate.items
return {
'code': 0,
'msg': '信息查询成功',
'count': paginate.total,
'data': [
{
'id': item.id,
'name': item.name,
'gender': item.gender,
'mobile': item.mobile,
'class_name': item.class_name,
'address': item.address,
'disable': item.disable,
'is_del': item.is_del,
'create_at': item.create_at.strftime('%Y-%m-%d %H:%M:%S'),
'update_at': item.update_at.strftime('%Y-%m-%d %H:%M:%S'),
} for item in items
]
}
2、后端返回静态页面
@app.route('/')
def hello_world():
return render_template('index.html')
前端部分
- 表格获取,数据渲染
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>学生信息管理系统</title>
<link rel="stylesheet" href="/static/css/layui.css" />
</head>
<body>
<div class="layui-container">
<table class="layui-hide" id="student"></table>
</div>
<script src="/static/layui.js"></script>
<script>
layui.use(function () {
var table = layui.table;
// 已知数据渲染
var inst = table.render({
elem: "#student",
id: "student",
url: "/api/student",
cols: [
[
// 标题栏
{ field: "id", title: "ID", width: 60, sort: true },
{ field: "name", title: "姓名", width: 100 },
{ field: "gender", title: "性别", width: 60 },
{ field: "class_name", title: "班级", width: 80 },
{ field: "mobile", title: "手机", width: 120 },
{ field: "address", title: "地址", minWidth: 160 },
{ field: "create_at", title: "创建时间", width: 200 },
{ field: "disable", title: "禁用", width: 100 },
{ field: "is_del", title: "删除", width: 80 },
],
],
page: true,
});
});
</script>
</body>
</html>
2、性别渲染
先定义渲染方法
function render_gender(d) {
if (d.gender === "M") {
return '<span style="color: blue">♂</span>';
} else {
return '<span style="color: pink">♀</span>';
}
}
再进行渲染
{field: 'gender', title: '性别', width: 60, templet: render_gender},
后面还有好几个字段需要进行渲染与修改,例如班级字段需要实现点击下拉选择,地址信息直接编辑修改,创建时间点击之后选择新的日期进行修改,禁用、删除用开关进行点击切换。关于这部分的内容,将放到最后进行修改。
新增学员信息
请求新增页面
- 添加表格头部栏新增按钮
- 添加新增案例的点击事件
- 前端发起请求,用 iframe 显示到新的页面
- 后端返回 html 模板
1、新增表格头部工具栏
<!-- 工具栏模板 -->
<script type="text/html" id="toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="add">添加</button>
<button class="layui-btn layui-btn-sm" lay-event="delete_many">删除</button>
</div>
</script>
2、添加表格工具栏事件
// 已知数据渲染
var inst = table.render({
elem: "#student",
id: "student",
url: "/api/student",
toolbar: "#toolbar",
cols: [
[
/*...*/
],
],
page: true,
});
3、添加点击事件
// 头部工具栏事件
table.on("toolbar(student)", function (obj) {
var options = obj.config; // 获取当前表格属性配置项
var checkStatus = table.checkStatus(options.id); // 获取选中行相关数据
// 根据不同的事件名进行相应的操作
switch (
obj.event // 对应模板元素中的 lay-event 属性值
) {
case "add":
window.show_add();
break;
case "delete_many":
window.delete_many(obj);
break;
}
});
window.show_add = function () {
layer.msg("添加");
};
window.delete_many = function (obj) {
layer.msg("批量删除");
};
4、显示新增表单
4.1、新建子页 html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<link rel="stylesheet" href="/static/css/layui.css" />
</head>
<body>
新增表单
<script src="/static/layui.js"></script>
<script>
layui.use(function () {
var $ = layui.$;
var form = layui.form;
});
</script>
</body>
</html>
4.2、后端返回模板
@app.get('/student_add')
def student_add():
return render_template('student_add.html')
4.3、前端发起请求
window.show_add = function () {
layer.open({
type: 2,
title: "新增学员",
shadeClose: true,
maxmin: true, //开启最大化最小化按钮
area: ["900px", "600px"],
content: "/student_add",
});
};
新增逻辑
- 添加新增表单
- 前端录入数据之后进行校验
- 校验成功之后提交到后端
- 后端接收数据添加到数据库
- 前端关闭添加页面
1、添加新增表单
<form
class="layui-form"
action=""
lay-filter="form_add"
style="margin-top: 20px"
>
<div class="layui-form-item">
<label class="layui-form-label">姓名</label>
<div class="layui-input-block">
<input
type="text"
name="name"
lay-verify="required"
autocomplete="off"
placeholder="请输入"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">性别</label>
<div class="layui-input-block">
<select name="gender" lay-verify="required">
<option value=""></option>
<option value="M">男</option>
<option value="F">女</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">班级</label>
<div class="layui-input-block">
<select name="class_name" lay-verify="required">
<option value=""></option>
<option value="一班">一班</option>
<option value="二班">二班</option>
<option value="三班">三班</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机号</label>
<div class="layui-input-block">
<input
type="text"
name="mobile"
lay-verify="required|phone"
autocomplete="off"
placeholder="请输入"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">地址</label>
<div class="layui-input-block">
<textarea
name="address"
class="layui-textarea"
placeholder="请输入地址"
></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input
type="text"
class="layui-input"
name="create_at"
id="create-at"
placeholder=""
autocomplete="off"
lay-verify="required"
/>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">禁用</label>
<div class="layui-input-block">
<input
type="checkbox"
name="disable"
lay-skin="switch"
lay-filter="switchTest"
title="是|否"
/>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button
type="submit"
class="layui-btn"
lay-submit
lay-filter="add-commit"
>
立即提交
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
2、监控提交事件
<script>
layui.use(function () {
var $ = layui.$;
var form = layui.form;
var laydate = layui.laydate;
// 提交事件
form.on("submit(add-commit)", function (data) {
var field = data.field; // 获取表单字段值
console.log(field);
// 此处可执行 Ajax 等操作
// …
return false; // 阻止默认 form 跳转
});
// 日期时间选择器
laydate.render({
elem: "#create-at",
type: "datetime",
});
});
</script>
3、检测数据并进行提交
// 新增提交的方法
const add_student = async (data) => {
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
const response = await fetch("/api/student", options);
return await response.json();
};
// 提交事件
form.on("submit(add-commit)", function (data) {
var field = data.field; // 获取表单字段值
console.log(field);
// 此处可执行 Ajax 等操作
field.disable = field?.disable ? true : false;
add_student(field).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(
ret.msg,
{
icon: 1,
time: 1000,
},
function () {
parent.layer.close(parent.layer.getFrameIndex(window.name)); //关闭当前页
parent.layui.table.reload("student");
},
);
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
});
// …
return false; // 阻止默认 form 跳转
});
4、后端模型添加方法
class StudentORM(db.Model):
...
def save(self):
db.session.add(self)
db.session.commit()
def update(self, data):
for key, value in data.items():
setattr(self, key, value)
5、接口完成新增逻辑
@app.post('/api/student')
def api_student_post():
data = request.get_json()
data['create_at'] = datetime.strptime(data['create_at'], '%Y-%m-%d %H:%M:%S')
student = StudentORM()
student.update(data)
try:
student.save()
except Exception as e:
return {
'code': -1,
'msg': '新增数据失败'
}
return {
'code': 0,
'msg': '新增数据成功'
}
修改学员信息
修改学员信息,因为表格中会加载完整的学员信息,所以在修改的时候可以在新的 iframe 页面请求数据加载,或者是利用原本已经加载的数据进行修改。
iframe 版本
这个版本与添加的逻辑差不多,只是需要多一次请求。因为大部分逻辑与新增差不多,在这里我就不写了,如果自己实现看下方的时序图即可。
单页版
单页面是利用原来表格中已有的数据,将其设置到之前已经定义好的表单中,然后将表单显示出来,修改完之后再将表单设置为空,然后影藏。
1、新增表格单元格事件
<!-- 表头某列 templet 属性指向的模板 -->
<script type="text/html" id="tools">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
挂载表格栏事件
{title: '操作', width: 120, templet: '#tools'}
2、添加编辑、删除事件
// 单元格工具事件
table.on("tool(student)", function (obj) {
var layEvent = obj.event; // 获得元素对应的 lay-event 属性值
if (layEvent === "edit") {
//编辑
window.show_edit(obj);
} else if (layEvent === "del") {
//删除
layer.confirm("确定删除吗?", function (index) {
layer.close(index);
window.del_student(obj);
});
}
});
window.show_edit = (obj) => {
layer.msg("显示编辑表单");
};
window.del_student = (obj) => {
layer.msg("删除学生数据");
};
3、新增修改表单
<form
class="layui-form"
action=""
id="form_edit"
lay-filter="form_edit"
style="margin-top: 20px;display: none"
>
<div class="layui-form-item" style="display: none">
<label class="layui-form-label">ID</label>
<div class="layui-input-block">
<input
type="text"
name="id"
lay-verify="required"
autocomplete="off"
placeholder="请输入"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">姓名</label>
<div class="layui-input-block">
<input
type="text"
name="name"
lay-verify="required"
autocomplete="off"
placeholder="请输入"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">性别</label>
<div class="layui-input-block">
<select name="gender" lay-verify="required">
<option value=""></option>
<option value="M">男</option>
<option value="F">女</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">班级</label>
<div class="layui-input-block">
<select name="class_name" lay-verify="required">
<option value=""></option>
<option value="一班">一班</option>
<option value="二班">二班</option>
<option value="三班">三班</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机号</label>
<div class="layui-input-block">
<input
type="text"
name="mobile"
lay-verify="required|phone"
autocomplete="off"
placeholder="请输入"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">地址</label>
<div class="layui-input-block">
<textarea
name="address"
class="layui-textarea"
placeholder="请输入地址"
></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input
type="text"
class="layui-input"
name="create_at"
id="create-at"
placeholder=""
autocomplete="off"
lay-verify="required"
/>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">禁用</label>
<div class="layui-input-block">
<input
type="checkbox"
name="disable"
lay-skin="switch"
lay-filter="switchTest"
title="是|否"
/>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button
type="submit"
class="layui-btn"
lay-submit
lay-filter="edit-commit"
>
立即提交
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
4、加载数据并显示表单
// 日期时间选择器
laydate.render({
elem: "#create-at",
type: "datetime",
});
window.show_edit = (obj) => {
console.log(obj.data);
form.val("form_edit", obj.data);
layer.open({
type: 1,
area: ["900px", "600px"],
content: $("#form_edit"), // 捕获的元素
});
};
5、校验数据并完成提交
// 新增提交的方法
const change_student = async (id, data) => {
const options = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
const response = await fetch(`/api/student/${id}`, options);
return await response.json();
};
// 提交事件
form.on("submit(edit-commit)", function (data) {
var field = data.field; // 获取表单字段值
// console.log(field)
// 此处可执行 Ajax 等操作
field.disable = field?.disable ? true : false;
change_student(field.id, field).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(
ret.msg,
{
icon: 1,
time: 1000,
},
function () {
layer.closeAll("page");
table.reload("student");
},
);
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
});
return false; // 阻止默认 form 跳转
});
6、后端完成修改
class StudentORM(db.Model):
...
def update(self, data):
for key, value in data.items():
setattr(self, key, value)
@app.put('/api/student/<int:sid>')
def api_student_put(sid):
data = request.get_json()
data['create_at'] = datetime.strptime(data['create_at'], '%Y-%m-%d %H:%M:%S')
# student = StudentORM.query.get(sid)
student = db.get_or_404(StudentORM, sid)
student.update(data)
try:
student.save()
except Exception as e:
return {
'code': -1,
'msg': '修改数据失败'
}
return {
'code': 0,
'msg': '修改数据成功'
}
7、表单恢复初始状态
这个可以做可以不做,因为下次显示的时候会再次覆盖
删除学员信息
删除数据时有两种方式,一种是物理删除,另一种是逻辑删除。物理删除就是从数据库中彻底删除,而逻辑删除则是在数据库中保留,但是不再显示给用户。就像被 404 的微信公众号文章,虽然在公众号上无法找到也无法查看,但是在腾讯的服务器中还保留着,说不定未来某一天还能再次看到。
1、前端请求删除
// 新增提交的方法
const del_student_api = async (id) => {
const options = {
method: "DELETE",
headers: { "Content-Type": "application/json" },
};
const response = await fetch(`/api/student/${id}`, options);
return await response.json();
};
window.del_student = (obj) => {
// console.log(obj)
del_student_api(obj.data.id).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(
ret.msg,
{
icon: 1,
time: 1000,
},
function () {
table.reload("student");
},
);
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
});
};
2、后端实现逻辑删除
@app.delete('/api/student/<int:sid>')
def api_student_del(sid):
student: StudentORM = db.get_or_404(StudentORM, sid)
try:
# db.session.delete(student)
student.is_del = True
db.session.commit()
except Exception as e:
return {
'code': -1,
'msg': '删除数据失败'
}
return {
'code': 0,
'msg': '删除数据成功'
}
3、查询学员的时候过滤以删除
在获取学员列表的方法里面过滤已经删除的数据,不再返回给前端。
修改学员单个信息
默认修改信息需要打开一个新的编辑页面进行操作,如果能够在表格上像 excel 一样修改,则会变得非常方便。而 layui 就提供了这么一套机制,可以直接在表格上进行修改。
修改班级
1、渲染班级列
<!-- 推荐 -->
<script type="text/html" id="TPL-dropdpwn-demo">
<button class="layui-btn layui-btn-sm layui-btn-primary dropdpwn-demo">
<span>{{ "{{= d.class_name }}"|safe }}</span>
<i class="layui-icon layui-icon-down layui-font-12"></i>
</button>
</script>
{field: 'class_name', title: '班级', width: 120, templet: '#TPL-dropdpwn-demo'},
2、渲染下拉组件
// 已知数据渲染
var inst = table.render({
elem: "#student",
// 表格渲染完之后再在里面渲染下拉框
done: function (res, curr, count) {
var options = this;
// 获取当前行数据
table.getRowData = function (elem) {
var index = $(elem).closest("tr").data("index");
return table.cache[options.id][index] || {};
};
// dropdown 方式的下拉选择
dropdown.render({
elem: ".dropdpwn-demo",
// trigger: 'hover',
// 此处的 data 值,可根据 done 返回的 res 遍历来赋值
data: [
{
title: "一班",
id: 100,
},
{
title: "二班",
id: 101,
},
{
title: "三班",
id: 102,
},
],
click: function (obj) {
var data = table.getRowData(this.elem); // 获取当前行数据(如 id 等字段,以作为数据修改的索引)
this.elem.find("span").html(obj.title);
// 更新数据中对应的字段
data.class_name = obj.title;
// 显示 - 仅用于演示
layer.msg(
"选中值: " + obj.title + "<br>当前行数据:" + JSON.stringify(data),
);
},
});
},
});
3、添加修改请求
const change_student_class_name = async (id, data) => {
const options = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
const response = await fetch(`/api/student/${id}/class_name`, options);
return await response.json();
};
change_student_class_name(data.id, { class_name: data.class_name }).then(
function (ret) {
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
});
} else {
layer.msg(
ret.msg,
{
icon: 2,
time: 1000,
},
function () {
table.reload("student");
},
);
}
},
);
4、后端完成修改
@app.put('/api/student/<int:sid>/class_name')
def api_student_class_name(sid):
student: StudentORM = db.get_or_404(StudentORM, sid)
data = request.get_json()
try:
student.class_name = data['class_name']
student.save()
except Exception as e:
return {
'code': -1,
'msg': '修改班级失败'
}
return {
'code': 0,
'msg': '修改班级成功'
}
修改地址
1、地址列设置为可以编辑
{field: 'address', title: '地址', minWidth: 160, edit: 'textarea'}
2、前端编辑事件
内容下载 table 的 done 方法里面
// 单元格普通编辑事件
table.on("edit(student)", function (obj) {
var value = obj.value; // 得到修改后的值
var data = obj.data; // 得到所在行所有键值
var field = obj.field; // 得到字段
var send_data = {};
send_data[field] = value;
const change_student_class_name = async (id, data) => {
const options = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
const response = await fetch(`/api/student/${id}/address`, options);
return await response.json();
};
change_student_class_name(data.id, send_data).then(function (ret) {
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
});
} else {
layer.msg(
ret.msg,
{
icon: 2,
time: 1000,
},
function () {
table.reload("student");
},
);
}
});
});
3、后端完成修改
@app.put('/api/student/<int:sid>/address')
def api_student_address(sid):
student: StudentORM = db.get_or_404(StudentORM, sid)
data = request.get_json()
try:
student.address = data['address']
student.save()
except Exception as e:
return {
'code': -1,
'msg': '修改地址失败'
}
return {
'code': 0,
'msg': '修改地址成功'
}
修改禁用状态
1、完成禁用列的渲染
function render_disable(d) {
return `<input type="checkbox" name="disable" value="${
d.id
}" title="是|否" lay-skin="switch" ${
d.disable ? "checked" : ""
} lay-filter="switch-disable"/>`;
}
{field: 'disable', title: '禁用', width: 100, templet: render_disable},
2、前端事件处理
form.on("switch(switch-disable)", function (obj) {
var value = this.value;
var name = this.name;
const send_data = {};
send_data[name] = !!obj.elem.checked;
const change_student_disable = async (id, data) => {
const options = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
};
const response = await fetch(`/api/student/${id}/disable`, options);
return await response.json();
};
change_student_disable(value, send_data).then(function (ret) {
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
});
} else {
layer.msg(
ret.msg,
{
icon: 2,
time: 1000,
},
function () {
table.reload("student");
},
);
}
});
});
3、后端完成修改
@app.put('/api/student/<int:sid>/disable')
def api_student_disable(sid):
student: StudentORM = db.get_or_404(StudentORM, sid)
data = request.get_json()
try:
student.disable = data['disable']
student.save()
except Exception as e:
return {
'code': -1,
'msg': '修改禁用失败'
}
return {
'code': 0,
'msg': '修改禁用成功'
}
表单查询
1、新建查询表单
<div class="layui-container">
<form
class="layui-form layui-row layui-col-space16"
style="margin: 20px 10px 20px"
>
<div class="layui-col-md4">
<div class="layui-input-wrap">
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-username"></i>
</div>
<input
type="text"
name="name"
value=""
placeholder="请输入姓名"
class="layui-input"
lay-affix="clear"
/>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-input-wrap">
<input
type="text"
name="mobile"
placeholder="请输入电话"
lay-affix="clear"
class="layui-input"
/>
</div>
</div>
<div class="layui-btn-container layui-col-xs12">
<button
class="layui-btn layui-btn-sm"
lay-submit
lay-filter="table-search"
>
查询
</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">
重置
</button>
</div>
</form>
</div>
2、追加表单搜索事件
// 搜索提交
form.on("submit(table-search)", function (data) {
var field = data.field; // 获得表单字段
// 执行搜索重载
table.reload("student", {
page: {
curr: 1, // 重新从第 1 页开始
},
where: field, // 搜索的字段
});
return false; // 阻止默认 form 跳转
});
3、改造后端逻辑,实现查询
@app.route('/api/student')
def student_view():
page = request.args.get('page', type=int, default=1)
per_page = request.args.get('per_page', type=int, default=10)
# paginate = StudentORM.query.paginate(page=page, per_page=per_page, error_out=False)
q = db.select(StudentORM)
name = request.args.get('name')
if name:
q = q.where(StudentORM.name == name)
paginate = db.paginate(q, page=page, per_page=per_page, error_out=False)
items: [StudentORM] = paginate.items
return {
'code': 0,
'msg': '信息查询成功',
'count': paginate.total,
'data': [
{
'id': item.id,
'name': item.name,
'gender': item.gender,
'mobile': item.mobile,
'class_name': item.class_name,
'address': item.address,
'disable': item.disable,
'is_del': item.is_del,
'create_at': item.create_at.strftime('%Y-%m-%d %H:%M:%S'),
'update_at': item.update_at.strftime('%Y-%m-%d %H:%M:%S'),
} for item in items
]
}