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>
界面效果

Flask + flask_sqlalchemy + jq 完成书籍展示、新增、删除功能的更多相关文章
- js jq 手机号实现(344) 附带删除功能 jq 实现银行卡没四个数加一个空格 附带删除功能
js 手机号实现(344) 下面有将正则验证去掉“-” 或“空格” 下一篇博客有单独的删除功能方法 <!DOCTYPE html> <head> <meta char ...
- PHP基础班初学心得:用JQ实现表单的全选、反选、取消和删除功能
摘要: 本人刚参加PHP基础班培训,由于之前毫无基础,分享的心得可能不规范,方法也许也"旁门左道",不能保证质量,只作自己总结学习,也希望能帮助到同样是初学者的朋友们,共同进步. ...
- SQL Server大量数据秒级插入/新增/删除
原文:SQL Server大量数据秒级插入/新增/删除 1.快速保存,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要保存的DataTable,该参数的TableName属性需要设置为数据库 ...
- Mybatis入门教程之新增、更新、删除功能_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 上一节说了Mybatis的框架搭建和简单查询,这次我们来说一说用Mybatis进行基本的增删改操作: 一. 插入一条数据 ...
- 实例:SSH结合Easyui实现Datagrid的批量删除功能
在我先前的基础上面添加批量删除功能.实现的效果如下 删除成功 通常情况下删除不应该真正删除,而是应该有一个标志flag,但flag=true表示状态可见,但flag=false表示状态不可见,为删除状 ...
- h5、jq 移动端评论点攒功能
h5.jq 移动端评论点攒功能 平时做的项目中大部分都会涉及到评论的功能,之前用angular写的项目,功能写起来很方便,但是对于一个单页来说,angular有点大材小用了,所有今天分享一个关于jq制 ...
- input file样式修改,图片预览删除功能
本篇对input file进行了修改,改成自己需要的样式,类似验证身份上传身份证图片的功能. 效果图如下: 这里主要展示上传预览图片功能,对于删除功能的html及css写的比较粗糙,对于想要精细表现这 ...
- sns社交系统ThinkSNS+ 更新至V0.8.2,新增圈子功能
sns社交系统"ThinkSNS+"于7月15日发布了V0.8.0,含开源版本web+H5,及Android APP和iOS APP客户端. V0.8.2版本将于7月29日(本周六 ...
- 安卓listView实现下拉刷新上拉加载滑动仿QQ的删除功能
大家对这些功能都是看的多了,然后对上拉刷新和下拉加载的原理都是非常清楚的,所以实现这功能其实也就是为了让大家能够从众多的同行们来进行比较学习而已,虽然即使是这样,但是面试的时候面试官还是会问你上拉和下 ...
随机推荐
- 用运oracel中的伪列rownum分页
在实际应用中我们经常碰到这样的问题,比如一张表比较大,我们只要其中的查看其中的前几条数据,或者对分页处理数据.在这些情况下我们都需要用到rownum.因此我们要理解rownum的原理和使用方法. Or ...
- springmvc资源文件访问不到,undefined,jsp引用js文件目录
资源访问失败: 该模块下springmvc.xml文件中添加配置: <mvc:resources mapping="/js/**" location="/js/&q ...
- HashMap、ConcurrentHashMap对比
1.hashmap的put的原理,hashmap的扩容及计算槽的算法,线程安全的hashtable.ConcurrentHashMap的区别是什么 1.1 hashMap的put原理 什么时候变成红黑 ...
- 【C++】结构体/结构体数组/结构体指针/结构体嵌套/函数参数/const
一.结构体声明 struct Student { //成员列表 string name; int age; int score; }; //s3;定义时直接声明 int main() { struct ...
- 如何查看Python的版本号
一.如何查看Python的版本号 win+r输入cmd在输入:python --version回车即可
- 学Java,Java书籍的最佳阅读顺序
疫情以来,好久没出差了,今天出差去趟上海,早上 4 点多就起床了,到机场天都没亮.到登机口离起飞还一小时,趁着等飞机的时间,抓紧码字,把这篇文章收个尾. 今天和大家说说学 Java 的读书路线.路线中 ...
- 扬我国威,来自清华的开源项目火爆Github
前几天TJ君跟大家分享了几个有趣的Github项目(加密解密.食谱.新冠序列,各种有趣的开源项目Github上都有),其中呢,有不少是来自斯坦福大学的项目,当时TJ君就不由得想,什么时候能看到的项目都 ...
- java面向对象类的继承~ 匿名类 ;多态特性;强制类型转换
类的继承 创建子类语法: 修饰符 class 子类名 extends 父类名{ } 匿名子类语法: 直接实例化,过程中通过匿名类 继承父类,在实例化过程中将子类匿名 <父类 ...
- 【LeetCode】916. Word Subsets 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/word-sub ...
- 【LeetCode】885. Spiral Matrix III 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...