百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python-Flask框架之图书管理系统项目 , 附详解源代码及效果图

ccwgpt 2024-09-15 15:05 35 浏览 0 评论



该图书管理系统要实现的功能如下

1. 可以通过添加窗口添加书籍或作者, 如果要添加的作者和书籍已存在于书架上, 则给出相应的提示.

2. 如果要添加的作者存在, 而要添加的书籍书架上没有, 则将该书籍添加到该作者栏.

3. 如果要添加的作者和书籍都不存在于书架上 , 则将书籍和作者一起添加.

4. 每个书籍和作者旁边都有一个删除按钮 , 点击删除书籍的按钮可以将该书籍删除 , 若某作者栏的书籍全部删除完毕则显示"无".

5. 若直接点击删除作者按钮, 则会将该作者和其书籍一起全部删除掉.

该系统的实现工具: Python的Flask框架以及MySQL数据库.

效果图如下

Python源代码如下

# coding=utf-8
from flask import Flask,render_template,request,flash,redirect,url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired

app = Flask(__name__)
"""
1. 配置数据库
    a.导入SQLALchemy扩展
    b.创建db对象, 并配置参数
    c.终端创建数据库
2. 添加作者和书模型(类)
    a.模型继承自db.Model
    b.__tablename__:表名
    c. db.Column:字段
    d. db.relationship:关系引用
3. 添加数据
4. 使用模板显示数据库查询到的数据
    a.查询所有的作者信息, 让信息传递给模板
    b.模板中按照格式, 依次for循环作者和书籍即可(通过作者获取书籍, 用的是关系引用)
5. 使用WTF显示表单 
    a.自定义表单类
    b.模板中显示
    c.设置secret_key
6. 实现相关的增删逻辑
    a.添加作者/书籍
    b.删除书籍: redirect(重定向)/url_for(指向路由)/for else  的使用.
    c.删除作者(要先删除该作者的书籍, 再删除该作者)
"""
# 配置数据库的地址URI , 格式 "数据库类型+数据库驱动名称://用户名:密码@机器地址:端口号/数据库名"  , 端口号可以不写.
# python3中用的mysql驱动是mysql-connector , 已经不支持python2的MySQLdb驱动.
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqlconnector://root:password@127.0.0.1/books_demo"
# 跟踪数据库的修改 --> 不建议开启 , 一是消耗性能 , 二是未来的版本中会移除.
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.secret_key = "hwhefsewljfejrlesjfl"      # 没设置secret_key会有报错提醒
# 将app作为参数传入这个关联工具 , 创建一个两者相关联对象db
db = SQLAlchemy(app)

# 注意: web框架里面的模型类基本都是要继承自导入的模块中的某个父类 , 这样才会起到关联的作用.
class Author(db.Model):
    """创建作者子类"""
    __tablename__ = "authors"           # 定义表名
    # 定义字段
    # db.Column表示是一个字段 , db.Integer就代表id这个字段的数据类型是整数 , primary_key代表主键(主关键字) , 是作为表的行的唯一标识.
    # db.String代表是字符串类型 , 字符串长度定义个n个字节 , unique(唯一的) , unique=True代表这列不允许出现重复的值.
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True)        # string的长度随便写个2的倍数就行了
    # 在"一对多"的一中定义author_book属性 , 该属性不会出现在字段中 , 后面的backref="author"是给Book反向引用的
    # 由于是"一对多" , 所以"多"的地方用Book参数 , "一"的地方用不加s的实例对象参数author.
    author_book = db.relationship("Book",backref="author")
    def __repr__(self):
        """返回定制消息, 与__str__作用类似"""
        return "Author: %d %s"%(self.id,self.name)

class Book(db.Model):
    """创建书籍子类"""
    __tablename__ = "books"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True)
    author_id = db.Column(db.Integer,db.ForeignKey("authors.id"))      # 表名.id 来建立外键关联
    def __repr__(self):
        return "Book: %d %s"%(self.id,self.name)

class TrueForm(FlaskForm):
    """表单扩展常用的模型(类)有三种: StringField, PasswordField,  SubmitField , 这里只用到两种
        然后传入参数并创建出各自的实例对象 , 以供其它地方使用.
    """
    author = StringField("作者",validators=[DataRequired()])
    book = StringField("书籍",validators=[DataRequired()])
    submit = SubmitField("添加")

def make_author_book():
    author1 = Author(name="金庸")
    author2 = Author(name="古龙")
    author3 = Author(name="鲁迅")
    author4 = Author(name="巴金")
    db.session.add_all([author1,author2,author3,author4])
    db.session.commit()
    book1 = Book(name="<<射雕英雄传>>", author_id=author1.id)
    book2 = Book(name="<<天龙八部>>", author_id=author1.id)
    book3 = Book(name="<<鹿鼎记>>", author_id=author1.id)
    book4 = Book(name="<<笑傲江湖>>", author_id=author1.id)
    book5 = Book(name="<<武林外史>>", author_id=author2.id)
    book6 = Book(name="<<萧十一郎>>", author_id=author2.id)
    book7 = Book(name="<<小李飞刀>>", author_id=author2.id)
    book8 = Book(name="<<狂人日记>>", author_id=author3.id)
    book9 = Book(name="<<阿Q正传>>", author_id=author3.id)
    book10 = Book(name="<<家>>", author_id=author4.id)
    book11 = Book(name="<<春>>", author_id=author4.id)
    book12 = Book(name="<<秋>>", author_id=author4.id)
    db.session.add_all([book1,book2,book3,book4,book5,book6,
                        book7,book8,book9,book10,book11,book12])
    db.session.commit()

@app.route("/",methods=["GET","POST"])
def add_author_book():
    true_form = TrueForm()
    """
    1.调用WTF的函数实现验证
    2.验证通过则获取数据
        3.判断作者是否存在
        4.如果作者存在, 则判断书籍是否存在, 没有重复的书籍就添加数据, 如果重复就提示错误.
        5.如果作者不存在, 就添加作者和书籍
    6.验证不通过就提示错误.
    """
    # 调用WTF的函数实现验证
    if true_form.validate_on_submit():
        # 2.验证通过则获取此时填入的数据
        author_name = true_form.author.data
        book_name = true_form.book.data
        # 3.判断作者是否存在, Author.query.filter_by(name=author_name)是查询, .first()才是拿到数据.
        author_query = Author.query.filter_by(name=author_name).first()
        # 4.如果作者存在
        if author_query:
            book_query = Book.query.filter_by(name=book_name).first()       # 查询并拿数据
            if book_query:
                flash("您要添加的书籍已存在!")
            else:
                try:
                    new_book = Book(name="<<%s>>"%book_name,author_id=author_query.id)
                    db.session.add(new_book)
                    db.session.commit()
                except Exception as e:
                    flash("添加书籍错误!")
                    db.session.rollback()      # 回滚操作
        else:
            # 5.如果作者不存在
            try:
                new_author = Author(name=author_name)
                db.session.add(new_author)
                db.session.commit()
                new_book = Book(name="<<%s>>"%book_name, author_id=new_author.id)
                db.session.add(new_book)
                db.session.commit()
            except Exception as e:
                flash("添加作者和书籍错误!")
                db.session.rollback()
    else:
        # 验证不通过
        if request.method == "POST":
            flash("参数错误!")
    # 查询所有的作者信息, 让信息传递给模板
    all_authors = Author.query.all()
    return render_template("book_manage.html",all_authors=all_authors,form=true_form)

# 网页中删除书籍-->将book_id参数传到路由, 路由再将book_id传入delete_book函数内部使用.
# < >尖括号代表路由参数, 路由需要接受参数
@app.route("/delete_book/<book_id>",methods=["GET","POST"])
def delete_book(book_id):
    # 1.查询书籍并拿数据
    book = Book.query.get(book_id)
    try:
        db.session.delete(book)
        db.session.commit()
    except Exception as e:
        flash("删除错误!")
        db.session.rollback()
    # redirect重定向回到根路径, redirect接收路由地址参数, 或者直接接收网址参数(http://xxxxx.com)
    # url_for("index"): 需要传入视图函数名, 返回该视图函数对应的路由地址(url)
    return redirect(url_for("add_author_book"))

# 删除作者
@app.route("/delete_author/<author_id>",methods=["GET","POST"])
def delete_author(author_id):
    # 1.查询作者并拿数据
    author = Author.query.get(author_id)
    try:
        # 查询书籍并删除, 直接在查询后面跟 .delete()就可以直接将查询到的结果删除掉
        Book.query.filter_by(author_id=author.id).delete()
        db.session.delete(author)
        db.session.commit()
    except Exception as e:
        flash("删除错误!")
        db.session.rollback()        # 回滚
    return redirect(url_for("add_author_book"))       # 重定向回到根路径


if __name__ == '__main__':
    # 先删除所有表, 在创建表之前要先删掉表
    db.drop_all()
    # 再创建所有表
    db.create_all()
    make_author_book()
    app.run(debug=True)

HTML源代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图书管理系统 | by-myself</title>
</head>
<body>
从此处添加书籍: <br>
<br>
<form method="post">
    {{ form.csrf_token() }}
                               {{form.author.label}} {{form.author}}<br>
                               {{form.book.label}} {{form.book}}<br>
                                                   {{form.submit}}<br>
    <br>
    {# 显示消息闪现的内容 #}
    {% for message in get_flashed_messages() %}
                                            {{message}}
    {%endfor%}
</form>
<br>
<hr>
<h1>                   书籍目录</h1>
<ul>
    <ul>
        <ul>
            {% for author in all_authors %}
                <li>{{author.name}}   <a href="{{url_for("delete_author",author_id=author.id)}}">删除</a></li>
                <ul>
                    {% for book in author.author_book %}
                        <li>{{book.name}}   <a href="{{ url_for("delete_book",book_id=book.id) }}">删除</a></li>
                    {% else %}
                        <li>无</li>
                    {% endfor %}
                </ul>
            {% endfor %}
        </ul>
    </ul>
</ul>
</body>
</html>

小结

该实战项目短小精悍, 麻雀虽小但五脏俱全, 虽没有精美的前端画面和复杂的页面功能, 但涵盖了基本的前后端交互, 以及动态的数据处理过程, 比较适合新手作为入门的练手项目。


声明: 该篇文章系本人原创作品, 欢迎点赞、转发和评论, 禁止转载, 谢谢配合!

相关推荐

团队管理“布阵术”:3招让你的团队战斗力爆表!

为何古代军队能够以一当十?为何现代企业有的团队高效似“特种部队”,有的却松散若“游击队”?**答案正隐匿于“布阵术”之中!**今时今日,让我们从古代兵法里萃取3个核心要义,助您塑造一支战斗力爆棚的...

知情人士回应字节大模型团队架构调整

【知情人士回应字节大模型团队架构调整】财联社2月21日电,针对原谷歌DeepMind副总裁吴永辉加入字节跳动后引发的团队调整问题,知情人士回应称:吴永辉博士主要负责AI基础研究探索工作,偏基础研究;A...

豆包大模型团队开源RLHF框架,训练吞吐量最高提升20倍

强化学习(RL)对大模型复杂推理能力提升有关键作用,但其复杂的计算流程对训练和部署也带来了巨大挑战。近日,字节跳动豆包大模型团队与香港大学联合提出HybridFlow。这是一个灵活高效的RL/RL...

创业团队如何设计股权架构及分配(创业团队如何设计股权架构及分配方案)

创业团队的股权架构设计,决定了公司在随后发展中呈现出的股权布局。如果最初的股权架构就存在先天不足,公司就很难顺利、稳定地成长起来。因此,创业之初,对股权设计应慎之又慎,避免留下巨大隐患和风险。两个人如...

消息称吴永辉入职后引发字节大模型团队架构大调整

2月21日,有消息称前谷歌大佬吴永辉加入字节跳动,并担任大模型团队Seed基础研究负责人后,引发了字节跳动大模型团队架构大调整。多名原本向朱文佳汇报的算法和技术负责人开始转向吴永辉汇报。简单来说,就是...

31页组织效能提升模型,经营管理团队搭建框架与权责定位

分享职场干货,提升能力!为职场精英打造个人知识体系,升职加薪!31页组织效能提升模型如何拿到分享的源文件:请您关注本头条号,然后私信本头条号“文米”2个字,按照操作流程,专人负责发送源文件给您。...

异形柱结构(异形柱结构技术规程)

下列关于混凝土异形柱结构设计的说法,其中何项正确?(A)混凝土异形柱框架结构可用于所有非抗震和抗震设防地区的一般居住建筑。(B)抗震设防烈度为6度时,对标准设防类(丙类)采用异形柱结构的建筑可不进行地...

职场干货:金字塔原理(金字塔原理实战篇)

金字塔原理的适用范围:金字塔原理适用于所有需要构建清晰逻辑框架的文章。第一篇:表达的逻辑。如何利用金字塔原理构建基本的金字塔结构受众(包括读者、听众、观众或学员)最容易理解的顺序:先了解主要的、抽象的...

底部剪力法(底部剪力法的基本原理)

某四层钢筋混凝土框架结构,计算简图如图1所示。抗震设防类别为丙类,抗震设防烈度为8度(0.2g),Ⅱ类场地,设计地震分组为第一组,第一自振周期T1=0.55s。一至四层的楼层侧向刚度依次为:K1=1...

结构等效重力荷载代表值(等效重力荷载系数)

某五层钢筋混凝土框架结构办公楼,房屋高度25.45m。抗震设防烈度8度,设防类别丙类,设计基本地震加速度0.2g,设计地震分组第二组,场地类别为Ⅱ类,混凝土强度等级C30。该结构平面和竖向均规则。假定...

体系结构已成昭告后世善莫大焉(体系构架是什么意思)

实践先行也理论已初步完成框架结构留余后人后世子孙俗话说前人栽树后人乘凉在夏商周大明大清民国共和前人栽树下吾之辈已完成结构体系又俗话说青出于蓝而胜于蓝各个时期任务不同吾辈探索框架结构体系经历有限肯定发展...

框架柱抗震构造要求(框架柱抗震设计)

某现浇钢筋混凝土框架-剪力墙结构高层办公楼,抗震设防烈度为8度(0.2g),场地类别为Ⅱ类,抗震等级:框架二级,剪力墙一级,混凝土强度等级:框架柱及剪力墙C50,框架梁及楼板C35,纵向钢筋及箍筋均采...

梁的刚度、挠度控制(钢梁挠度过大会引起什么原因)

某办公楼为现浇钢筋混凝土框架结构,r0=1.0,混凝土强度等级C35,纵向钢筋采用HRB400,箍筋采用HPB300。其二层(中间楼层)的局部平面图和次梁L-1的计算简图如图1~3(Z)所示,其中,K...

死要面子!有钱做大玻璃窗,却没有钱做“柱和梁”,不怕房塌吗?

活久见,有钱做2层落地大玻璃窗,却没有钱做“柱子和圈梁”,这样的农村自建房,安全吗?最近刷到个魔幻施工现场,如下图,这栋5开间的农村自建房,居然做了2个全景落地窗仔细观察,这2个落地窗还是飘窗,为了追...

不是承重墙,物业也不让拆?话说装修就一定要拆墙才行么

最近发现好多朋友装修时总想拆墙“爆改”空间,别以为只要避开承重墙就能随便砸!我家楼上邻居去年装修,拆了阳台矮墙想扩客厅,结果物业直接上门叫停。后来才知道,这种配重墙拆了会让阳台承重失衡,整栋楼都可能变...

取消回复欢迎 发表评论: