该图书管理系统要实现的功能 :html
1. 能够经过添加窗口添加书籍或做者, 若是要添加的做者和书籍已存在于书架上, 则给出相应的提示.python
2. 若是要添加的做者存在, 而要添加的书籍书架上没有, 则将该书籍添加到该做者栏.mysql
3. 若是要添加的做者和书籍都不存在于书架上 , 则将书籍和做者一块儿添加.web
4. 每一个书籍和做者旁边都有一个删除按钮 , 点击删除书籍的按钮能够将该书籍删除 , 若某做者栏的书籍所有删除完毕则显示"无".sql
5. 若直接点击删除做者按钮, 则能够将该做者和其书籍一块儿所有删掉.数据库
该系统的实现工具: Python的Flask框架和MySQL数据库.flask
效果图及源码以下:session
Python源代码以下:app
# 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-陈彬</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>