Skip to content

Python开发阶段考试

图书管理系统-Python 开发阶段综合考试

考试流程

  1. 需求讲解。
  2. 思路讲解。
  3. 小组练习考试,因为本次涉及到知识点较多。实现的优先级为: 1. 后端(比较重要必须要完成。) 1. 前端(根据情况选做,也可以直接使用老师提供的前端代码。)
  4. 小组答辩与老师点评。

需求分析

项目简介

图书管理系统用于管理图书馆或图书收藏的软件系统。它帮助图书管理员和用户进行图书的管理。

实现方式

项目需要完成后端接口开发及前端页面的开发。如果你有更好的实现方式,可以尝试实现。

后端接口开发

基于 Flask 框架,完成图书管理系统接口设计。

前端页面开发

基于后台实现的接口,开发前端页面,将接口返回数据进行展示。

知识点

基础知识
  • Python 基础语法
  • Python 面向对象
后端接口开发
  • Flask 框架
  • 接口路由技术
  • 模板技术
  • 请求与响应数据处理
  • 蓝图与视图
  • 数据与 ORM 框架
前端页面开发
  • HTML
  • CSS
  • JavaScript
  • JQuery

业务功能梳理

后端接口开发
  • 图书管理系统实现对图书信息增、删、改、查、搜索等功能。
  • 需要接收请求参数并进行处理
  • 需要根据不同的请求查询数据库完成不同数据的返回
  • 数据使用数据库进行保存
前端页面开发
  • 图书管理系统实现对图书信息增、删、改、查、搜索等功能的页面。
  • 需要在页面中请求对应的接口数据并进行展示

实现思路

uml diagram

项目需求

后端接口开发

数据库准备
  1. 创建本地数据库。
  2. 创建数据表 book, 包含如下字段:
    • bid(编号,主键自动增长)
    • name(书名,字符型)
    • price(单价,浮点型)
    • summary(概要,可变长度字符型)
    • quantity(库存,整型),
后端服务接口
  1. 使用 Flask 完成图书管理系统后台设计
  2. 使用 蓝图 完成图书管理系统路由接口设计
  3. 实现 添加,修改,删除,列表显示,搜索等功能的对应接口
  1. 列表接口
    • 接口地址:/book/list
    • GET请求方式: 以 JSON 格式返回所有图书数据在首页列表显示
  2. 添加接口

    • 接口地址:/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

需求描述

后端接口开发

  1. 根据需求实现各接口

前端页面开发

  1. 实现首页
    • 首页需包含添加功能页面跳转链接,搜索功能输入框及按钮,数据展示列表。
    • 不允许使用 table 表格标签展示数据,但需要使用表格的形式展示/list 接口返回的数据
    • 在首页中展示搜索接口 /book/search 返回的搜索结果数据
    • 首页中可以点击链接跳转至添加页面
    • 在每条记录后的修改链接可以跳转至该记录的修改页面
    • 在每条记录后的删除链接可以删除该记录
  2. 实现添加页面
    • 输入数据,并可以成功向数据库中添加数据
    • 添加数据后自动跳转回首页显示添加结果
  3. 实现修改页面
    • 在修改页面中回显需要修改记录的数据
    • 输入数据,可以将修改后的数据更新至数据库
    • 修改数据后自动跳转回首页显示修改结果

实现步骤

后端接口实现

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>