后端代码

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>

界面效果

 

Flask + flask_sqlalchemy + jq 完成书籍展示、新增、删除功能的更多相关文章

  1. js jq 手机号实现(344) 附带删除功能 jq 实现银行卡没四个数加一个空格 附带删除功能

    js 手机号实现(344)  下面有将正则验证去掉“-” 或“空格”  下一篇博客有单独的删除功能方法 <!DOCTYPE html> <head> <meta char ...

  2. PHP基础班初学心得:用JQ实现表单的全选、反选、取消和删除功能

    摘要: 本人刚参加PHP基础班培训,由于之前毫无基础,分享的心得可能不规范,方法也许也"旁门左道",不能保证质量,只作自己总结学习,也希望能帮助到同样是初学者的朋友们,共同进步. ...

  3. SQL Server大量数据秒级插入/新增/删除

    原文:SQL Server大量数据秒级插入/新增/删除 1.快速保存,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要保存的DataTable,该参数的TableName属性需要设置为数据库 ...

  4. Mybatis入门教程之新增、更新、删除功能_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 上一节说了Mybatis的框架搭建和简单查询,这次我们来说一说用Mybatis进行基本的增删改操作: 一. 插入一条数据 ...

  5. 实例:SSH结合Easyui实现Datagrid的批量删除功能

    在我先前的基础上面添加批量删除功能.实现的效果如下 删除成功 通常情况下删除不应该真正删除,而是应该有一个标志flag,但flag=true表示状态可见,但flag=false表示状态不可见,为删除状 ...

  6. h5、jq 移动端评论点攒功能

    h5.jq 移动端评论点攒功能 平时做的项目中大部分都会涉及到评论的功能,之前用angular写的项目,功能写起来很方便,但是对于一个单页来说,angular有点大材小用了,所有今天分享一个关于jq制 ...

  7. input file样式修改,图片预览删除功能

    本篇对input file进行了修改,改成自己需要的样式,类似验证身份上传身份证图片的功能. 效果图如下: 这里主要展示上传预览图片功能,对于删除功能的html及css写的比较粗糙,对于想要精细表现这 ...

  8. sns社交系统ThinkSNS+ 更新至V0.8.2,新增圈子功能

    sns社交系统"ThinkSNS+"于7月15日发布了V0.8.0,含开源版本web+H5,及Android APP和iOS APP客户端. V0.8.2版本将于7月29日(本周六 ...

  9. 安卓listView实现下拉刷新上拉加载滑动仿QQ的删除功能

    大家对这些功能都是看的多了,然后对上拉刷新和下拉加载的原理都是非常清楚的,所以实现这功能其实也就是为了让大家能够从众多的同行们来进行比较学习而已,虽然即使是这样,但是面试的时候面试官还是会问你上拉和下 ...

随机推荐

  1. 【Linux】【Services】【Web】Nginx基础

    1. 概念 1.1. 消息通知机制:同步synchronous,异步asynchronous 同步:等待对方返回信息 异步:被调用者通过状态.通知或回调通知调用者 状态:调用者每隔一段时间就需要检查一 ...

  2. SQL错误总结

    ORA-00918: column ambiguously defined 异常原因: select 查询的字段在from的两张表中都存在,导致数据库无法区别需要查询的字段来自于哪张表 以下是例子 s ...

  3. Hystrix断路器中的服务熔断与服务降级

    一.Hystrix断路器 微服务架构特点就是多服务,多数据源,支撑系统应用.这样导致微服务之间存在依赖关系.如果其中一个服务故障,可能导致系统宕机,这就是所谓的雪崩效应. 1.为什么需要断路器 服务雪 ...

  4. libev I/O事件

    libev是来实现reactor模式,主要包含三大部分: 1. watcher:watcher是Reactor中的Event Handler. 作用:1)向事件循环提供了统一的调用接口(按类型区分) ...

  5. M函数目录(Power Query 之 M 语言)

    2021-12-11更新 主页(选项卡) 管理列(组) 选择列 选择列Table.SelectColumns 删除列 删除列Table.RemoveColumns 删除其他列Table.SelectC ...

  6. 逻辑判断(Power Query 之 M 语言)

    逻辑真:true 逻辑假:false 与函数:and true and true,结果为TRUE true and false,结果为FALSE false and false,结果为FALSE 或函 ...

  7. 新建任务(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 新建任务,这操作简单得就跟在Excel的单元格里输入个数据一样,不过也不是一点讲究都没有. 首先得选对视图. 不是所有的视 ...

  8. LuoguP7094 [yLOI2020] 金陵谣 题解

    Content 有 \(t\) 组询问,每组询问给定四个整数 \(a,b,c,d\),请求出满足 \[\dfrac{a}{x}+\dfrac{b}{c}=\dfrac{d}{y} \] 的正整数对 \ ...

  9. java 图形化小工具Abstract Window Toolit 画笔 处理位图

    具体编程来处理位图 知识点: 实现逻辑: 画板上的图片 new BufferedImage(canvasWidth,canvasHeight,BufferedImage.TYPE_INT_BGR); ...

  10. 原生XMLHTTPResponse,jQuery-Ajax 上传文件;iframe上传图片&预览;图片验证码小案例

    原生AJAX Ajax主要就是使用 [XmlHttpRequest]对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件) 1.Xml ...