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
]
}