Python-Flask框架之"圖書管理系統"項目,附詳解源代碼及頁面效果截圖
該圖書管理系統要實現的功能如下:
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-陳彬</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>

浙公網安備 33010602011771號