Python-Flask框架之——圖書管理系統 , 附詳解源碼和效果圖 !

該圖書管理系統要實現的功能 :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() }}
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{form.author.label}}&nbsp;{{form.author}}<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{form.book.label}}&nbsp;{{form.book}}<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{form.submit}}<br>
    <br>
    {# 顯示消息閃現的內容 #}
    {% for message in get_flashed_messages() %}
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{message}}
    {%endfor%}
</form>
<br>
<hr>
<h1>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;書籍目錄</h1>
<ul>
    <ul>
        <ul>
            {% for author in all_authors %}
                <li>{{author.name}}&nbsp;&nbsp;&nbsp;<a href="{{url_for("delete_author",author_id=author.id)}}">刪除</a></li>
                <ul>
                    {% for book in author.author_book %}
                        <li>{{book.name}}&nbsp;&nbsp;&nbsp;<a href="{{ url_for("delete_book",book_id=book.id) }}">刪除</a></li>
                    {% else %}
                        <li></li>
                    {% endfor %}
                </ul>
            {% endfor %}
        </ul>
    </ul>
</ul>
</body>
</html>
相關文章
相關標籤/搜索