Flask + flask_sqlalchemy + jq 完成书籍展示、新增、删除功能

后端代码

from flask import Flask, render_template, request, jsonify
from flask_wtf.csrf import CSRFProtect
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)

# 使用防csrf保护APP
csrf = CSRFProtect(app)


class Config(object):
    # sqlalchemy的配置参数
    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123456@192.168.3.58:3306/test"

    # 设置sqlalchemy自动更跟踪数据库
    SQLALCHEMY_TRACK_MODIFICATIONS = True

    SECRET_KEY = "doiso7fd89fyd9^(fsd"


app.config.from_object(Config)
db = SQLAlchemy(app)


# 定义作者模型类
class Author(db.Model):
    __tablename__ = "tbl_author"

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))


# 定义书籍模型类
class Book(db.Model):
    __tablename__ = "tbl_book"

    id = db.Column(db.Integer, primary_key=True)
    book_name = db.Column(db.String(50))
    author_id = db.Column(db.Integer)


@app.route("/")
def index():
    book_num = db.session.query(Book).all()
    if not book_num:
        return render_template("book.html", books=[], page_list=[])
    page_num = len(book_num)//10
    if len(book_num) % 10 > 0:
        page_num += 1
    page_list = range(1, page_num + 1)
    page = request.args.get("page")
    if not page:
        page = 1
    else:
        page = int(page)

    # 查询数据
    ret_list = db.session.query(Book.id, Book.book_name, Author.name)\
        .outerjoin(Author, Book.author_id == Author.id).order_by(Book.id)\
        .slice((page-1)*10, page*10)\
        .all()
    return render_template("book.html", books=ret_list, page_list=page_list)


@csrf.exempt      # 取消csrf保护
@app.route("/del", methods=["POST"])
def delete():
    """删除书籍"""
    # 提取参数
    # 如果前端发送的请求体数据是json格式,get_json会解析成字典
    # get_json 要求前端传送的数据的Content-Type: application/json
    req_dict = request.get_json()
    book_id = int(req_dict.get("book_id"))
    if book_id == '':
        resp_data = {"code": 1, "msg": "传入的id为空", "data": {}}
        return jsonify(resp_data)

    books_id = db.session.query(Book.id).all()

    if (book_id,) not in books_id:
        resp_data = {"code": 1, "msg": "删除的书籍不存在", "data": {}}
        return jsonify(resp_data)

    # 删除数据
    book = db.session.query(Book).get(book_id)
    db.session.delete(book)
    db.session.commit()

    # 构造响应数据
    resp_data = {"code": 0, "msg": "删除成功", "data": {}}
    return jsonify(resp_data)


@app.route("/add", methods=["POST"])
def add():
    """增加书籍"""
    # 获取请求信息
    req_dict = request.get_json()
    book_name = req_dict.get("name")
    author_name = req_dict.get("author")
    # 检查请求信息是否为空
    if not all([book_name, author_name]):
        # 为空则提示
        resp_data = {"code": 1, "msg": "输入的数据不能为!", "data": {}}
        return jsonify(resp_data)

    # 检查作者名称是否存在
    authors_name = db.session.query(Author.name).all()
    new_author = None
    new_id = None
    if (author_name,) not in authors_name:
        # 不存在就创建
        new_id = db.session.query(Author.id).order_by(-Author.id).first()[0] + 1
        new_author = Author(id=new_id, name=author_name)
        # 将新增数据加入会话中,等待最后一起提交
        db.session.add(new_author)

    # 获取作者的id
    if new_author:
        author_id = new_id
    else:
        author_id = db.session.query(Author.id).filter(Author.name == author_name).one()[0]

    # 检查请求的书名
    books_name = db.session.query(Book.book_name).filter(Book.author_id == author_id).all()
    if (book_name,) in books_name:
        # 存在则提示
        resp_data = {"code": 1, "msg": "书籍已存在", "data": {}}
        return jsonify(resp_data)

    new_book = Book(book_name=book_name, author_id=author_id)
    db.session.add(new_book)

    # 留个长度超长BUG,验证该异常
    try:
        db.session.commit()
        resp_data = {"code": 0, "msg": "创建成功", "data": {}}
        return resp_data
    except Exception as e:
        db.session.rollback()
        resp_data = {"code": 1, "msg": F"提交失败:{e}", "data": {}}
        return resp_data


if __name__ == '__main__':
    # 删除所有表格(慎用)
    # db.drop_all()
    # db.create_all()

    app.run()

模板代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--  如果开启csrf保护,需要定义如下代码  -->
   <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>book_info</title>
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <script>
        $(function(){
            var book_name = $("#book_name")
            var book_author = $("#book_author")
            var csrftoken = $('meta[name=csrf-token]').attr('content')
            $.ajaxSetup({
                beforeSend: function(xhr, settings) {
                    if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
                        xhr.setRequestHeader("X-CSRFToken", csrftoken)
                    }
                }
            });

            // 获取URL后参数的值,name为参数名
            $.getUrlParam = function (name) {
                var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
                var r = window.location.search.substr(1).match(reg);
                if (r != null) return unescape(r[2]); return null;
            }
            var current_page = $.getUrlParam("page")
            
            // 定义ajax请求函数
            var req_post = function(url, data){
                // 将js中的对象转换为 json字符串
                var req_json = JSON.stringify(data);
                $.ajax({
                    url: url,
                    type: "post",
                    // 申明传给后端的字符类型
                    contentType: "application/json",
                    dataType: 'json',
                    data: req_json
                }).done(function(resp){
                    if (resp.code == 0)
                    {
                        if ( current_page != null){
                            if (url == "/del" && $(".del").length == 1 && current_page > 1){
                                current_page = current_page - 1
                                location.href = "/?page=" + current_page
                            }else{
                                location.href = "/?page=" + current_page
                            }
                        }else{
                            location.href = "/"
                        }
                    }
                    alert(resp.msg)
                }).fail(function(){
                    console.log("请求失败")
                });
            };

            // 创建书籍
            $("#book_create").click(function(){
                b_name = book_name.val();
                b_author = book_author.val();
                var data = {'name': b_name, 'author': b_author};
                req_post("/add", data)
            });

            // 删除书籍
            $(".del").click(function(){
                var id = $(this).siblings()[0].innerHTML;
                var data = {'book_id': id}
                console.log("删除id为:" + id)
                req_post("/del",data)
            });

            // 分页
            $(".page div").click(function(){
                var page_num = $(this)[0].innerHTML;
                var data = "page=" + page_num
                location.href = "/?" + data
            });
        })
    </script>
    <style>
        * {
            font-size: 16px;
        }
        #add {
            margin-top: 50px;
            margin-left: 100px;
            float: left;
        }

        #add div {
            width: 400px;
            margin: 10px auto 0px;
        }

        #book_name, #book_author {
            width: 200px;
            border: 1px solid #000;
        }
        
        #book_create {
            width: 100px;
            margin: auto;
        }

        #book {
            width: 500px;
            background-color: rgba(113, 255, 161, 0.952);
            margin-left: 50px;
            float: left;
        };

        .th, .tr {
            width: 500px;
            height: 20px;
        }

        .th div, .tr div{
            width: 200px;
            height: 30px;
            float: left;
            text-align: center;
            line-height: 30px;
        }

        .clearfix:before,.clearfix:after{
            content:"";
            display:table;
        }
        .clearfix:after{
            clear:both;
        }
        .clearfix{
            zoom:1;
        }

        div.del{
            width: 100px;
            color: rgb(49, 0, 185);
        }

        div.th3 {
            width: 100px;
        }


        .del:hover, .page div:hover{
            cursor: pointer;
        }

        .page {
            width: 280px;
            height: 20px;
            margin: 20px;
        }

        .page div {
            width: 20px;
            height: 20px;
            float: left;
            margin: 0px 5px;
            text-align: center;
            line-height: 20px;
        }

    </style>
</head>
<body>
<div id="app">
    <div id="add">
        <div>书籍名称:<input type="text" id="book_name"></div> 
        <div>书籍作者:<input type="text" id="book_author"></div>
        <div><input type="submit" id="book_create" value="新增"></div>
    </div>
    <div id="book">
        <div class="th clearfix">
            <div>书籍名称</div>
            <div>作者</div>
            <div class="th3">操作</div>
        </div>
        {% for book in books %}
        <div class="tr clearfix">
            <div style="display: none;">{{ book[0] }}</div>
            <div>{{ book[1] }}</div>
            <div>{{ book[2] }}</div>
            <div  class="del" >删除</div>
        </div>
        {% endfor %}
        <div class="page">
            {% for page in page_list %}
                <div>{{ page }}</div>

            {% endfor %}
        </div>
    </div>
</div>
</body>
</html>

界面效果

 

 
posted @ 2020-12-14 22:57  码上测  阅读(201)  评论(0编辑  收藏  举报