Python开发阶段考试
图书管理系统-Python 开发阶段综合考试
考试流程
- 需求讲解。
- 思路讲解。
- 小组练习考试,因为本次涉及到知识点较多。实现的优先级为: 1. 后端(比较重要必须要完成。) 1. 前端(根据情况选做,也可以直接使用老师提供的前端代码。)
- 小组答辩与老师点评。
需求分析
项目简介
图书管理系统用于管理图书馆或图书收藏的软件系统。它帮助图书管理员和用户进行图书的管理。
实现方式
项目需要完成后端接口开发及前端页面的开发。如果你有更好的实现方式,可以尝试实现。
后端接口开发
基于 Flask 框架,完成图书管理系统接口设计。
前端页面开发
基于后台实现的接口,开发前端页面,将接口返回数据进行展示。
知识点
基础知识
- Python 基础语法
- Python 面向对象
后端接口开发
- Flask 框架
- 接口路由技术
- 模板技术
- 请求与响应数据处理
- 蓝图与视图
- 数据与 ORM 框架
前端页面开发
- HTML
- CSS
- JavaScript
- JQuery
业务功能梳理
后端接口开发
- 图书管理系统实现对图书信息增、删、改、查、搜索等功能。
- 需要接收请求参数并进行处理
- 需要根据不同的请求查询数据库完成不同数据的返回
- 数据使用数据库进行保存
前端页面开发
- 图书管理系统实现对图书信息增、删、改、查、搜索等功能的页面。
- 需要在页面中请求对应的接口数据并进行展示
实现思路
项目需求
后端接口开发
数据库准备
- 创建本地数据库。
- 创建数据表 book, 包含如下字段:
- bid(编号,主键自动增长)
- name(书名,字符型)
- price(单价,浮点型)
- summary(概要,可变长度字符型)
- quantity(库存,整型),
后端服务接口
- 使用 Flask 完成图书管理系统后台设计
- 使用 蓝图 完成图书管理系统路由接口设计
- 实现 添加,修改,删除,列表显示,搜索等功能的对应接口
- 列表接口
- 接口地址:
/book/list
GET请求方式
: 以 JSON 格式返回所有图书数据在首页列表显示
- 接口地址:
-
添加接口
- 接口地址:
/book/add
POST 请求方式
: 以 JSON 格式返回所有图书数据,包含新添加的数据 6. 修改接口- 接口地址:
book/update
POST 请求方式
: 以 JSON 格式返回所有图书数据包含修改后的数据,且图书 id 不可修改。 7. 修改回显数据接口- 接口地址:
/book/<id>
GET 请求方式
: 以 JSON 格式返回修改图书在修改页面回显的数据 8. 删除接口- 接口地址:
/book/delete/<id>
- 所有删除相关请求需要携带要删除图书的 ID 信息
GET 请求方式
: 删除指定图书信息并在列表页显示删除后的结果 9. 搜索接口- 接口地址:
/book/search
GET 请求方式
: 以 JSON 格式返回搜索结果- 搜索功能中可以通过 name 字段进行搜索
- 接口地址:
前端页面开发
数据接口地址
-
首页列表接口:
/book/list
- 请求方式: GET
- 返回数据: JSON
-
搜索接口:
/book/search
- 请求方式: GET
- 请求参数:
wd=搜索输入内容
- 返回数据: JSON
-
添加接口:
/book/add
- 请求方式: POST
- 响应体参数:
name
,price
,summary
,quantity
- 返回数据: JSON
-
修改接口:
/book/update
- 请求方式: POST
- 响应体参数:
name
,price
,summary
,quantity
- 返回数据: JSON
-
回显数据接口:
/book/get/<id>
- 请求方式: GET
- 返回数据: JSON
- 删除接口:
/book/delete/<id>
- 请求方式: GET
- 返回数据: JSON
需求描述
后端接口开发
- 根据需求实现各接口
前端页面开发
- 实现首页
- 首页需包含添加功能页面跳转链接,搜索功能输入框及按钮,数据展示列表。
- 不允许使用
table
表格标签展示数据,但需要使用表格的形式展示/list
接口返回的数据 - 在首页中展示搜索接口
/book/search
返回的搜索结果数据 - 首页中可以点击链接跳转至添加页面
- 在每条记录后的修改链接可以跳转至该记录的修改页面
- 在每条记录后的删除链接可以删除该记录
- 实现添加页面
- 输入数据,并可以成功向数据库中添加数据
- 添加数据后自动跳转回首页显示添加结果
- 实现修改页面
- 在修改页面中回显需要修改记录的数据
- 输入数据,可以将修改后的数据更新至数据库
- 修改数据后自动跳转回首页显示修改结果
实现步骤
后端接口实现
Flask 服务器配置
Server.py
# 定义 app
from flask import Flask
from flask_cors import CORS
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
# 声明app实例
app = Flask(__name__)
app.json.ensure_ascii = False # 解决中文乱码问题
# 解决跨域问题
CORS(app, supports_credentials=True)
# 声明数据库相关
engine = create_engine(f"sqlite+pysqlite:///book.db", echo=True)
session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)
@app.before_request
def before_request():
# 在每个请求前执行的代码
Session()
@app.teardown_request
def teardown_request(exception=None):
# 在每个请求后执行的代码
if exception:
Session.rollback()
Session.remove()
if __name__ == '__main__':
from backend.book_router import book_manager
# 运行服务
app.register_blueprint(book_manager)
app.run(debug=True)
ORM 配置
在 book_models.py
中添加 orm 数据表:
Base = declarative_base()
# 定义一个ORM模型类
class Book(Base):
__tablename__ = 'book' # 数据库表名
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String)
price = Column(Float)
summary = Column(String)
quantity = Column(Integer)
if __name__ == '__main__':
# 创建数据库表
Base.metadata.create_all(engine)
蓝图配置
BookBP.py
from flask import Blueprint, request
from backend.book_models import Book, BookModel
from backend.server import Session
# 注册蓝图
book_manager = Blueprint("book", __name__, url_prefix="/book")
# 获取书籍接口
@book_manager.get(f"/<int:book_id>")
def get_book(book_id):
student_data = Session.query(Book).filter_by(id=book_id).first()
if student_data is None:
return {"errcode": 10001, "errmsg": f"图书信息id:{book_id}获取数据不存在"}
student_dict = BookModel.model_validate(student_data).model_dump()
return {"errcode": 0, "datas": student_dict, "errmsg": f"获取图书信息id为{book_id}信息成功"}
# 新建书籍
@book_manager.post("/add")
def create_book():
create_json = request.form.to_dict()
# 新建的时候id通过自增
# 数据校验
BookModel.model_validate(create_json)
Session.add(Book(**create_json))
Session.commit()
return {"errcode": 0, "errmsg": "创建图书信息成功"}
# 更新书籍
@book_manager.post("/update")
def update_book():
update_json = request.form.to_dict()
# 数据校验
student_model = BookModel.model_validate(update_json)
# 获取图书信息数据
if Session.query(Book).filter_by(id=student_model.id).first() is None:
return {"errcode": 10001, "errmsg": f"图书信息id:{student_model.id}获取数据不存在"}
Session.query(Book).filter_by(id=student_model.id).update(student_model.model_dump())
Session.commit()
return {"errcode": 0, "errmsg": "修改图书信息成功"}
# 删除书籍
@book_manager.get("/delete/<int:book_id>")
def delete_book(book_id):
student_data = Session.query(Book).filter_by(id=book_id).first()
if student_data is None:
return {"errcode": 10001, "errmsg": f"图书信息id:{book_id}获取数据不存在"}
Session.delete(student_data)
Session.commit()
return {"errcode": 0, "errmsg": "删除图书信息成功"}
# 获取全部
@book_manager.get("/list")
def get_book_list():
students = Session.query(Book).all()
datas = [BookModel.model_validate(s).model_dump() for s in students]
return {"errcode": 0, "datas": datas, "errmsg": "查询图书信息成功"}
# 根据名称查找
@book_manager.get("/search")
def get_book_list_by_name():
name = request.args.get("name")
students = Session.query(Book).filter_by(name=name).all()
datas = [BookModel.model_validate(s).model_dump() for s in students]
return {"errcode": 0, "datas": datas, "errmsg": "查询图书信息成功"}
前端页面实现
首页列表页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页面</title>
<style>
.main{
width: 1200px;
height: 800px;
margin: 50px auto;
}
.op{
padding: 10px 30px;
display: flex;
justify-content: space-between;
}
a{
text-decoration: none;
}
.title{
font-size: 30px;
text-align: center;
width: 1200px;
height: 80px;
line-height: 80px;
}
/* .content table{
width: 1200px;
text-align: center;
border-collapse: collapse;
}
tr, th, td{
border: 1px solid #000;
}
.cell span{
color: blue;
} */
.content .table{
/* width: 1200px; */
text-align: center;
}
.tr{
width: 1200px;
height: 50px;
line-height: 50px;
display: flex;
justify-content: space-between;
}
.th, .td{
/* width: 200px; */
flex: 1;
text-align: center;
border: 1px solid #000;
}
.tr .td:nth-child(4), .tr .th:nth-child(4){
flex: 2;
}
</style>
<!-- 引入 jquery -->
<script src="./static/jquery-3.7.1.min.js"></script>
<script>
// 在入口事件中请求页面显示的数据
$(function(){
$.get("http://127.0.0.1:5000/book/list",function(data){
// div 展示数据
setDivContent(data)
});
});
// 查找函数
function search(){
// 获取查询关键词
var wd = $(".wd").val()
// 发起请求获取搜索数据
$.get("http://127.0.0.1:5000/book/search",{"name": wd},function(data){
// div 展示数据
setDivContent(data)
},"json");
}
// 添加数据方法
function setDivContent(data){
console.log(data)
data = data.datas
// 拼接页面展示数据及元素布局
html_str = ""
// 拼接表头
html_str += "<div class='tr'>"
html_str += " <div class='th'>编号</div>"
html_str += " <div class='th'>书名</div>"
html_str += " <div class='th'>价格</div>"
html_str += " <div class='th'>简介</div>"
html_str += " <div class='th'>库存</div>"
html_str += " <div class='th'>操作</div>"
html_str += "</div>"
// 遍历数据,拼接数据行表格中的行
for(var i =0;i<data.length;i++){
var obj = data[i]
html_str += "<div class='tr'>"
html_str += " <div class='td'> " + obj.id + " </div>"
html_str += " <div class='td'> " + obj.name + " </div>"
html_str += " <div class='td'> " + obj.price + " </div>"
html_str += " <div class='td'> " + obj.summary + " </div>"
html_str += " <div class='td'> " + obj.quantity + " </div>"
html_str += " <div class='td'><a href='update.html?id=" + obj.id + "'>编辑</a> | <a href='http://127.0.0.1:5000/book/delete/" + obj.id + "'>删除</a></div>"
html_str += "</div>"
}
// 将数据添加到页面中
$(".data").html(html_str)
}
</script>
</head>
<body>
<!-- 页面主体 -->
<div class="main">
<!-- 标题 -->
<div class="title">图书管理系统</div>
<!-- 功能条 -->
<div class="op">
<!-- 添加按钮 -->
<div class="add"><a href="add.html">添加图书</a></div>
<!-- 搜索框 -->
<div class="search">
<input type="text" class="wd" placeholder="请根据名称搜索">
<input type="button" value="搜索" onclick="search()">
</div>
</div>
<!-- 内容展示区域 -->
<div class="content">
<div class="data">
</div>
</div>
</div>
</body>
</html>
添加页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增页面</title>
<style>
.main{
width: 1200px;
height: 800px;
margin: 0 auto;
border: 1px solid #000;
}
.title{
font-size: 30px;
text-align: center;
}
.data{
width: 1200px;
text-align: center;
}
.data div{
margin-top: 30px;
}
</style>
</head>
<body>
<div class="main">
<div class="title">添加图书</div>
<div class="data">
<!-- 提交数据表单 -->
<form action="http://127.0.0.1:5000/book/add" method="post">
<div>书名: <input type="text" placeholder="请输入书名" name="name"></div>
<div>价格: <input type="text" placeholder="请输入价格" name="price"></div>
<div>简介: <input type="text" placeholder="请输入简介" name="summary"></div>
<div>库存: <input type="text" placeholder="请输入库存" name="quantity"></div>
<div> <input type="submit" value="添加"></div>
</form>
</div>
</div>
</body>
</html>
修改页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书-修改</title>
<style>
.main{
width: 1200px;
height: 800px;
margin: 0 auto;
border: 1px solid #000;
}
.title{
font-size: 30px;
text-align: center;
}
.data{
width: 1200px;
text-align: center;
}
.data div{
margin-top: 30px;
}
</style>
<script src="static/jquery-3.7.1.min.js"></script>
<script>
// 通过入口事件,请求回显示数据,并展示到修改页面中
$(function(){
var url = window.location.href
var id = url.substring(url.lastIndexOf("=")+1)
$.get("http://127.0.0.1:5000/book/"+id,function(data){
console.log(data)
var data = data.datas
$(".id").val(data.id)
$(".name").val(data.name)
$(".price").val(data.price)
$(".summary").val(data.summary)
$(".quantity").val(data.quantity)
// 拼接提交地址,并设置到表单的 action 属性中
var url = "http://127.0.0.1:5000/book/update"
$("form").prop({"action":url})
},"json");
});
</script>
</head>
<body>
<div class="main">
<div class="title">修改图书信息</div>
<div class="data">
<!-- 提交修改数据 -->
<form action="http://127.0.0.1:5000/book/update" method="post">
<div>编号: <input type="text" class="id" name="id" readonly></div>
<div>书名: <input type="text" class="name" name="name"></div>
<div>价格: <input type="text" class="price" name="price"></div>
<div>简介: <input type="text" class="summary" name="summary"></div>
<div>库存: <input type="text" class="quantity" name="quantity"></div>
<div> <input type="submit" value="修改"></div>
</form>
</div>
</div>
</body>
</html>