Python+MySQL 图书管理系统超级简单简略版

数据库代码:

CREATE DATABASE tushuguanlixitong1;
use tushuguanlixitong1;
CREATE TABLE books (
    book_id INT PRIMARY KEY AUTO_INCREMENT,        -- 图书编号(主键,自增)
    book_name VARCHAR(255) NOT NULL,               -- 图书名
    book_status VARCHAR(50) NOT NULL,              -- 图书状态(如:在架、出借)
    book_ISBN VARCHAR(20) UNIQUE NOT NULL,         -- ISBN
    author VARCHAR(255),                           -- 作者
    press VARCHAR(255),                            -- 出版社
    borrower VARCHAR(255),                         -- 借阅者姓名(如果有的话)
    loan_time DATE                                 -- 借出时间
);
CREATE TABLE reader (
    reader_id INT PRIMARY KEY AUTO_INCREMENT,      -- 读者编号(主键,自增)
    read_name VARCHAR(255) NOT NULL,               -- 读者姓名
    read_identity VARCHAR(100),                    -- 读者身份(如:学生、教师)
    read_department VARCHAR(255)                   -- 读者所在部门
);
CREATE TABLE borrow_records (
    record_id INT PRIMARY KEY AUTO_INCREMENT,      -- 借阅记录编号(主键,自增)
    book_id INT,                                   -- 图书编号(外键,关联到 books 表)
    borrower VARCHAR(255) NOT NULL,                 -- 借阅者姓名
    borrow_date DATE NOT NULL,                      -- 借出日期
    return_date DATE,                               -- 归还日期(如果归还的话)
    FOREIGN KEY (book_id) REFERENCES books(book_id) -- 外键约束
);

INSERT INTO books (book_name, book_status, book_ISBN, author, press)
VALUES
('Python编程', '在架', '978-7-111-60680-2', '张三', '人民邮电出版社'),
('数据结构与算法', '在架', '978-7-111-62057-1', '李四', '高等教育出版社'),
('数据库系统概论', '在架', '978-7-111-48459-9', '王五', '清华大学出版社');

INSERT INTO reader (read_name, read_identity, read_department)
VALUES
('王五', '学生', '计算机科学与技术'),
('李四', '教师', '软件工程'),
('张三', '学生', '数据科学');

INSERT INTO borrow_records (book_id, borrower, borrow_date, return_date)
VALUES
(1, '王五', '2024-12-01', NULL),  -- 王五借了《Python编程》,未归还
(2, '李四', '2024-12-02', '2024-12-10'),  -- 李四借了《数据结构与算法》,已归还
(3, '张三', '2024-12-05', NULL);  -- 张三借了《数据库系统概论》,未归还

Python代码(但是感觉还有好多漏洞 还有很多需要完善的地方 可能还有些隐藏逻辑错误没发现 以后有待指正):

import pymysql
import datetime

connection = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    passwd='shurumima',
    db='tushuguanlixitong1',
    charset='utf8'
)

def query(sql, one = False): #执行 SQL 查询并返回查询结果  sql:一个字符串,包含要执行的 SQL 查询语句。
    cursor = connection.cursor() #创建一个游标对象,cursor 用于执行 SQL 查询并处理结果。游标是 Python 与数据库之间的桥梁,通过它可以执行查询、更新操作等。
    cursor.execute(sql) #执行传入的 SQL 查询语句 sql
    if one:
        return cursor.fetchone() #返回查询结果集中的第一条记录,返回类型是元组(tuple),包含一行数据。如果没有更多数据,它返回 None
    else:
        return cursor.fetchall() #返回查询结果集中的所有记录,返回类型是一个列表,每一项是一个元组,表示每一行数据。如果查询结果为空,则返回一个空列表 []。

def update(sql): #执行数据库中的修改操作,比如 INSERT、UPDATE 或 DELETE 等操作
    cursor = connection.cursor()
    result = cursor.execute(sql) #result 保存了 cursor.execute(sql) 执行后的返回值,通常是影响的行数(即数据库中受该操作影响的记录数量)。对于 UPDATE 和 DELETE 操作,result 返回被修改或删除的行数。对于 INSERT 操作,result 返回插入的记录数。
    connection.commit() #提交事务,将之前执行的 SQL 操作(比如 UPDATE、DELETE、INSERT)的修改永久保存到数据库中。
    return result

def select_book():
    cursor = connection.cursor()
    #定义 SQL 查询语句,从图书信息表表中选择所有数据
    sql = 'select * from books;'
    cursor.execute(sql)
    connection.commit() #对于查询操作来说这行代码并不必要(因为查询操作通常不需要提交),但如果做了数据修改(例如INSERT、UPDATE、DELETE),这行代码是必须的。
    #从游标中获取查询结果,保存到 data 变量中
    data = cursor.fetchall()
    from pandas import DataFrame
    #这些列名应该和数据库表中的列名称一致。
    df = DataFrame(data, columns=['book_name', 'book_id', 'book_status', 'book_ISBN', 'author', 'press', 'borrower',
                                  'loan_time'])
    df.head() #返回 DataFrame 的前五行数据。head() 是 pandas 提供的一个方法,用于查看数据框的前几行(默认为前5行)。
    print(df.head())

class Book:
    def __init__(self, book_name, book_id, book_status, book_isbn, author, press):
        self.book_name = book_name
        self.book_id = book_id
        self.book_status = book_status
        self.book_ISBN = book_isbn
        self.author = author
        self.press = press

def add_book():
    cursor = connection.cursor()
    sql = 'insert into books(book_name,book_id,book_status,book_ISBN,author,press) values(%s,%s,%s,%s,%s,%s)'
    print('请输入添加图书信息:')
    book = Book(None, None, None, None, None, None)
    book.book_name = input('请输入图书名:')
    book.book_id = input('请输入图书编号:')
    book.book_status = input('请输入图书状态:')
    book.book_ISBN = input('请输入图书ISBN码:')
    book.author = input('请输入图书作者:')
    book.press = input('请输入图书出版社:')
    values = (book.book_name, book.book_id, book.book_status, book.book_ISBN, book.author, book.press)
    cursor.execute(sql, values)
    connection.commit()
    print('图书添加成功')

def delete_book():
    connection.cursor()
    book_id = input('输入需要删除的图书号:')
    # query 是自定义函数,见上面
    result = query('select * from books where book_id = {}'.format(book_id), one=True)
    if result:
        print('图书信息:', result)
        choice = input('是否删除? 1.yes,2.no')
        if choice == '1':
            update('delete from books where book_id = {}'.format(book_id))
            print('成功删除')
        else:
            print('放弃删除')
    else:
        print('未查询到相关书籍信息')

    num = input('继续删除请输入1, 回车退回主菜单')
    if num == '1':
        delete_book()

def update_book():
    connection.cursor()
    book_id = input('输入需要更新的图书号:')
    result = query('select * from books where book_id = {}'.format(book_id), one=True)
    if result:
        print('图书信息:', result)
        book_name = input('请输入修改书名:')
        book_status = input('请输入图书状态:')
        author = input('请输入修改作者:')
        press = input('请输入修改出版社:')
        update("update books set book_name = '{}',book_status = '{}',author = '{}',press = '{}' where book_id = {};".format(book_name, book_status, author, press, book_id))
        print('更新成功')
    else:
        print('未查询到相关书籍信息')

    num = input('继续修改请输入1, 回车退回主菜单')
    if num == '1':
        update_book()

def select_reader():
    cursor = connection.cursor()
    sql = 'select * from reader;'
    cursor.execute(sql)
    connection.commit()
    data = cursor.fetchall()
    from pandas import DataFrame
    df = DataFrame(data, columns=['姓名', '编号', '身份', '部门'])
    df.head()
    print(df.head())

class Read:
    def __init__(self, read_name, read_id, read_identity, read_department):
        self.read_name = read_name
        self.read_id = read_id
        self.read_identity = read_identity
        self.read_department = read_department

def add_reader():
    cursor = connection.cursor()
    sql = 'insert into reader(read_name,read_id,read_identity,read_department) values(%s,%s,%s,%s)'
    print('添加人员:')
    read = Read(None, None, None, None)
    read.read_name = input('请输入读者姓名')
    read.read_id = input('请输入读者编号')
    read.read_identity = input('请输入读者身份')
    read.read_department = input('请输入读者所在部门')
    values = (read.read_name, read.read_id, read.read_identity, read.read_department)
    cursor.execute(sql, values)
    connection.commit()
    print('读者添加成功!')

def borrow_book():
    cursor = connection.cursor()
    book_id = input('请输入需要借阅的图书号:')
    result = query('select * from books where book_id={};'.format(book_id), one=True)
    if result:
        if result[2] == '出借':
            print('抱歉,该书已经借出!')
        else:
            borrower = input('请输入借阅者的名字:')
            borrow_date = datetime.datetime.now().strftime('%Y-%m-%d')
            return_date = None
            sql = 'insert into borrow_records (book_id, borrower, borrow_date, return_date) values (%s, %s, %s, %s)'
            values = (book_id, borrower, borrow_date, return_date)
            cursor.execute(sql, values)
            connection.commit()
            update("update books set book_status='出借' where book_id={};".format(book_id))
            print('图书借阅成功')
    else:
        print('未查询到相关书籍信息')

    num = input('继续借书请输入1, 回车退回主菜单')
    if num == '1':
        borrow_book()

def back_book():
    cursor = connection.cursor()
    book_id = input('请输入要归还的图书书号:')
    result = query('select * from books where book_id={};'.format(book_id), one=True)
    if result:
        if result[2] == '在架':
            print('抱歉,该书在架,请确认编号是否正确!')
        else:
            borrow_record = query('select * from borrow_records where book_id={} and return_date IS NULL order by borrow_date desc limit 1'.format(book_id), one=True)
            #使用 query() 函数查询 borrow_records 表,找到该图书的借阅记录。要求 book_id 匹配并且 return_date 为 NULL(表示该书尚未归还)。order by borrow_date desc 确保查询返回的是最新的借阅记录,limit 1 限制查询返回一条记录。
            if borrow_record: #如果查询到借阅记录(即图书有借阅且未归还),则执行图书归还操作。
                return_date = datetime.datetime.now().strftime('%Y-%m-%d')
                cursor.execute('update borrow_records set return_date=%s where record_id=%s', (return_date, borrow_record[0]))  #record_id 是借阅记录的 ID
                connection.commit()
                update("update books set book_status='在架' where book_id={};".format(book_id))
                print('归还成功')
            else:
                print('未找到该书的借阅记录')
    else:
        print('未查询到相关书籍信息')

    num = input('继续还书请输入1,回车退回主菜单')
    if num == '1':
        back_book()

def time():
    cursor = connection.cursor()
    now = datetime.datetime.now()
    # 查询超期图书(归还时间小于当前时间且未归还)
    cursor.execute("""
        select b.book_name, br.borrower, br.borrow_date, br.return_date 
        from borrow_records br
        join books b on br.book_id = b.book_id
        where br.return_date < %s and br.return_date IS NOT NULL
    """, (now,))
    overdue_books = cursor.fetchall()
    if overdue_books:
        print('超期图书:')
        for book in overdue_books:
            print(f"书名: {book[0]}, 借阅者: {book[1]}, 借阅时间: {book[2]}, 归还时间: {book[3]}")
    else:
        print('没有超期的图书。')
    # 查询临期图书(归还时间在10天内)
    cursor.execute("""
        select b.book_name, br.borrower, br.borrow_date, br.return_date 
        from borrow_records br
        join books b on br.book_id = b.book_id
        where br.return_date between %s and %s
    """, (now, now + datetime.timedelta(days=10)))
    due_soon_books = cursor.fetchall()

    if due_soon_books:
        print('临期图书:')
        for book in due_soon_books:
            print(f"书名: {book[0]}, 借阅者: {book[1]}, 借阅时间: {book[2]}, 归还时间: {book[3]}")
    else:
        print('没有临期的图书。')

def menu():
    while True:
        print("""
                   图书管理系统
           1.查询图书
           2.增加图书
           3.借阅图书
           4.归还图书
           5.修改图书
           6.删除图书
           7.导入读者名单
           8.查看读者名单
           9.超期和临期查询
           10.退出系统
           """)
        choice = input('请选择:')

        if choice == '1':
            select_book()
        elif choice == '2':
            add_book()
        elif choice == '3':
            borrow_book()
        elif choice == '4':
            back_book()
        elif choice == '5':
            update_book()
        elif choice == '6':
            delete_book()
        elif choice == '7':
            add_reader()
        elif choice == '8':
            select_reader()
        elif choice == '9':
            time()
        elif choice == '10':
            print('欢迎下次使用')
            break
        else:
            print('请输入正确序号')

menu()

在delete_book()函数中,
①参考的代码中写的错误代码:

 print("图书信息:".format(result))

正确:

print("图书信息:", result)
print(f"图书信息:{result}")
print("图书信息:{}".format(result))

②注意:在将 book_id 插入 SQL 查询时,使用 .format() 的方式可能会引发 SQL 注入攻击。
③注意:在 delete_book() 中使用递归调用(delete_book())来实现删除图书的功能。如果用户选择继续删除,会导致递归调用,但如果删除的操作很多,可能会引起栈溢出问题。可以考虑使用循环代替递归。

在borrow_book()函数中,
①datetime.datetime.now()
datetime 是 Python 标准库中的一个模块,用于处理日期和时间。
datetime.datetime 是 datetime 模块中的一个类,表示日期和时间。
now() 是 datetime 类的一个方法,用于获取当前的日期和时间,返回一个 datetime 对象。
strftime('%Y-%m-%d')
strftime 是 datetime 类中的一个方法,用于将 datetime 对象格式化为字符串。
strftime 方法接受一个格式字符串作为参数,表示你希望日期和时间如何被表示成字符串。
在这个例子中,格式字符串是 '%Y-%m-%d',它指定了日期的输出格式:
'%Y' 表示四位的年份(例如,2024)。
'%m' 表示两位的月份(例如,12)。
'%d' 表示两位的日期(例如,17)。

cursor.execute(query, parameters)

query:一个字符串,表示要执行的 SQL 查询或命令。这个字符串可以是 SELECT 查询、INSERT 语句、UPDATE 语句、DELETE 语句等。
parameters(可选):一个元组或字典,包含传递给 SQL 语句的参数。这些参数通常用于防止 SQL 注入攻击,确保数据库操作的安全性。
对于 MySQL 和 PostgreSQL,占位符通常是 %s(无论传递的参数类型是什么)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353