后端代码
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>
界面效果