后端代码

  1. from flask import Flask, render_template, request, jsonify
  2. from flask_wtf.csrf import CSRFProtect
  3. from flask_sqlalchemy import SQLAlchemy
  4.  
  5. app = Flask(__name__)
  6.  
  7. # 使用防csrf保护APP
  8. csrf = CSRFProtect(app)
  9.  
  10. class Config(object):
  11. # sqlalchemy的配置参数
  12. SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123456@192.168.3.58:3306/test"
  13.  
  14. # 设置sqlalchemy自动更跟踪数据库
  15. SQLALCHEMY_TRACK_MODIFICATIONS = True
  16.  
  17. SECRET_KEY = "doiso7fd89fyd9^(fsd"
  18.  
  19. app.config.from_object(Config)
  20. db = SQLAlchemy(app)
  21.  
  22. # 定义作者模型类
  23. class Author(db.Model):
  24. __tablename__ = "tbl_author"
  25.  
  26. id = db.Column(db.Integer, primary_key=True)
  27. name = db.Column(db.String(50))
  28.  
  29. # 定义书籍模型类
  30. class Book(db.Model):
  31. __tablename__ = "tbl_book"
  32.  
  33. id = db.Column(db.Integer, primary_key=True)
  34. book_name = db.Column(db.String(50))
  35. author_id = db.Column(db.Integer)
  36.  
  37. @app.route("/")
  38. def index():
  39. book_num = db.session.query(Book).all()
  40. if not book_num:
  41. return render_template("book.html", books=[], page_list=[])
  42. page_num = len(book_num)//10
  43. if len(book_num) % 10 > 0:
  44. page_num += 1
  45. page_list = range(1, page_num + 1)
  46. page = request.args.get("page")
  47. if not page:
  48. page = 1
  49. else:
  50. page = int(page)
  51.  
  52. # 查询数据
  53. ret_list = db.session.query(Book.id, Book.book_name, Author.name)\
  54. .outerjoin(Author, Book.author_id == Author.id).order_by(Book.id)\
  55. .slice((page-1)*10, page*10)\
  56. .all()
  57. return render_template("book.html", books=ret_list, page_list=page_list)
  58.  
  59. @csrf.exempt # 取消csrf保护
  60. @app.route("/del", methods=["POST"])
  61. def delete():
  62. """删除书籍"""
  63. # 提取参数
  64. # 如果前端发送的请求体数据是json格式,get_json会解析成字典
  65. # get_json 要求前端传送的数据的Content-Type: application/json
  66. req_dict = request.get_json()
  67. book_id = int(req_dict.get("book_id"))
  68. if book_id == '':
  69. resp_data = {"code": 1, "msg": "传入的id为空", "data": {}}
  70. return jsonify(resp_data)
  71.  
  72. books_id = db.session.query(Book.id).all()
  73.  
  74. if (book_id,) not in books_id:
  75. resp_data = {"code": 1, "msg": "删除的书籍不存在", "data": {}}
  76. return jsonify(resp_data)
  77.  
  78. # 删除数据
  79. book = db.session.query(Book).get(book_id)
  80. db.session.delete(book)
  81. db.session.commit()
  82.  
  83. # 构造响应数据
  84. resp_data = {"code": 0, "msg": "删除成功", "data": {}}
  85. return jsonify(resp_data)
  86.  
  87. @app.route("/add", methods=["POST"])
  88. def add():
  89. """增加书籍"""
  90. # 获取请求信息
  91. req_dict = request.get_json()
  92. book_name = req_dict.get("name")
  93. author_name = req_dict.get("author")
  94. # 检查请求信息是否为空
  95. if not all([book_name, author_name]):
  96. # 为空则提示
  97. resp_data = {"code": 1, "msg": "输入的数据不能为!", "data": {}}
  98. return jsonify(resp_data)
  99.  
  100. # 检查作者名称是否存在
  101. authors_name = db.session.query(Author.name).all()
  102. new_author = None
  103. new_id = None
  104. if (author_name,) not in authors_name:
  105. # 不存在就创建
  106. new_id = db.session.query(Author.id).order_by(-Author.id).first()[0] + 1
  107. new_author = Author(id=new_id, name=author_name)
  108. # 将新增数据加入会话中,等待最后一起提交
  109. db.session.add(new_author)
  110.  
  111. # 获取作者的id
  112. if new_author:
  113. author_id = new_id
  114. else:
  115. author_id = db.session.query(Author.id).filter(Author.name == author_name).one()[0]
  116.  
  117. # 检查请求的书名
  118. books_name = db.session.query(Book.book_name).filter(Book.author_id == author_id).all()
  119. if (book_name,) in books_name:
  120. # 存在则提示
  121. resp_data = {"code": 1, "msg": "书籍已存在", "data": {}}
  122. return jsonify(resp_data)
  123.  
  124. new_book = Book(book_name=book_name, author_id=author_id)
  125. db.session.add(new_book)
  126.  
  127. # 留个长度超长BUG,验证该异常
  128. try:
  129. db.session.commit()
  130. resp_data = {"code": 0, "msg": "创建成功", "data": {}}
  131. return resp_data
  132. except Exception as e:
  133. db.session.rollback()
  134. resp_data = {"code": 1, "msg": F"提交失败:{e}", "data": {}}
  135. return resp_data
  136.  
  137. if __name__ == '__main__':
  138. # 删除所有表格(慎用)
  139. # db.drop_all()
  140. # db.create_all()
  141.  
  142. app.run()

模板代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <!-- 如果开启csrf保护,需要定义如下代码 -->
  6. <meta name="csrf-token" content="{{ csrf_token() }}">
  7. <title>book_info</title>
  8. <script src="/static/js/jquery-1.12.4.min.js"></script>
  9. <script>
  10. $(function(){
  11. var book_name = $("#book_name")
  12. var book_author = $("#book_author")
  13. var csrftoken = $('meta[name=csrf-token]').attr('content')
  14. $.ajaxSetup({
  15. beforeSend: function(xhr, settings) {
  16. if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
  17. xhr.setRequestHeader("X-CSRFToken", csrftoken)
  18. }
  19. }
  20. });
  21.  
  22. // 获取URL后参数的值,name为参数名
  23. $.getUrlParam = function (name) {
  24. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
  25. var r = window.location.search.substr(1).match(reg);
  26. if (r != null) return unescape(r[2]); return null;
  27. }
  28. var current_page = $.getUrlParam("page")
  29.  
  30. // 定义ajax请求函数
  31. var req_post = function(url, data){
  32. // 将js中的对象转换为 json字符串
  33. var req_json = JSON.stringify(data);
  34. $.ajax({
  35. url: url,
  36. type: "post",
  37. // 申明传给后端的字符类型
  38. contentType: "application/json",
  39. dataType: 'json',
  40. data: req_json
  41. }).done(function(resp){
  42. if (resp.code == 0)
  43. {
  44. if ( current_page != null){
  45. if (url == "/del" && $(".del").length == 1 && current_page > 1){
  46. current_page = current_page - 1
  47. location.href = "/?page=" + current_page
  48. }else{
  49. location.href = "/?page=" + current_page
  50. }
  51. }else{
  52. location.href = "/"
  53. }
  54. }
  55. alert(resp.msg)
  56. }).fail(function(){
  57. console.log("请求失败")
  58. });
  59. };
  60.  
  61. // 创建书籍
  62. $("#book_create").click(function(){
  63. b_name = book_name.val();
  64. b_author = book_author.val();
  65. var data = {'name': b_name, 'author': b_author};
  66. req_post("/add", data)
  67. });
  68.  
  69. // 删除书籍
  70. $(".del").click(function(){
  71. var id = $(this).siblings()[0].innerHTML;
  72. var data = {'book_id': id}
  73. console.log("删除id为:" + id)
  74. req_post("/del",data)
  75. });
  76.  
  77. // 分页
  78. $(".page div").click(function(){
  79. var page_num = $(this)[0].innerHTML;
  80. var data = "page=" + page_num
  81. location.href = "/?" + data
  82. });
  83. })
  84. </script>
  85. <style>
  86. * {
  87. font-size: 16px;
  88. }
  89. #add {
  90. margin-top: 50px;
  91. margin-left: 100px;
  92. float: left;
  93. }
  94.  
  95. #add div {
  96. width: 400px;
  97. margin: 10px auto 0px;
  98. }
  99.  
  100. #book_name, #book_author {
  101. width: 200px;
  102. border: 1px solid #000;
  103. }
  104.  
  105. #book_create {
  106. width: 100px;
  107. margin: auto;
  108. }
  109.  
  110. #book {
  111. width: 500px;
  112. background-color: rgba(113, 255, 161, 0.952);
  113. margin-left: 50px;
  114. float: left;
  115. };
  116.  
  117. .th, .tr {
  118. width: 500px;
  119. height: 20px;
  120. }
  121.  
  122. .th div, .tr div{
  123. width: 200px;
  124. height: 30px;
  125. float: left;
  126. text-align: center;
  127. line-height: 30px;
  128. }
  129.  
  130. .clearfix:before,.clearfix:after{
  131. content:"";
  132. display:table;
  133. }
  134. .clearfix:after{
  135. clear:both;
  136. }
  137. .clearfix{
  138. zoom:1;
  139. }
  140.  
  141. div.del{
  142. width: 100px;
  143. color: rgb(49, 0, 185);
  144. }
  145.  
  146. div.th3 {
  147. width: 100px;
  148. }
  149.  
  150. .del:hover, .page div:hover{
  151. cursor: pointer;
  152. }
  153.  
  154. .page {
  155. width: 280px;
  156. height: 20px;
  157. margin: 20px;
  158. }
  159.  
  160. .page div {
  161. width: 20px;
  162. height: 20px;
  163. float: left;
  164. margin: 0px 5px;
  165. text-align: center;
  166. line-height: 20px;
  167. }
  168.  
  169. </style>
  170. </head>
  171. <body>
  172. <div id="app">
  173. <div id="add">
  174. <div>书籍名称:<input type="text" id="book_name"></div>
  175. <div>书籍作者:<input type="text" id="book_author"></div>
  176. <div><input type="submit" id="book_create" value="新增"></div>
  177. </div>
  178. <div id="book">
  179. <div class="th clearfix">
  180. <div>书籍名称</div>
  181. <div>作者</div>
  182. <div class="th3">操作</div>
  183. </div>
  184. {% for book in books %}
  185. <div class="tr clearfix">
  186. <div style="display: none;">{{ book[0] }}</div>
  187. <div>{{ book[1] }}</div>
  188. <div>{{ book[2] }}</div>
  189. <div class="del" >删除</div>
  190. </div>
  191. {% endfor %}
  192. <div class="page">
  193. {% for page in page_list %}
  194. <div>{{ page }}</div>
  195.  
  196. {% endfor %}
  197. </div>
  198. </div>
  199. </div>
  200. </body>
  201. </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】【Basis】用户、组和权限管理

    1. 概念: 1.1. 每个使用者都有,用户标识UID和密码:并且有身份(Authentication),授权(Authorization),审计(Audition):组(用户组,用户容器) 1.2. ...

  2. 使用beanUtils封装对象的servlet

    package com.hopetesting.web.servlet;import com.hopetesting.dao.UserDao;import com.hopetesting.domain ...

  3. 团队协作项目——SVN的使用

    参考文献:https://www.cnblogs.com/rwh871212/p/6955489.html 老师接了一个新项目,需要团队共同完成开发任务,因此需要SVN.SVN是C/S架构: 1.服务 ...

  4. Markdown随时记录

    Markdown学习 推荐文本编译器 Typora 标题(支持六级) 一级标题:# + 空格 + 内容 二级标题:## + 空格 + 内容 三级标题:### + 空格 + 内容 . . . 字体 粗体 ...

  5. 编译工具sbt部署

    目录 一.简介 二.部署 三.测试 一.简介 项目构建工具是项目开发中非常重要的一个部分,充分利用好它能够极大的提高项目开发的效率.在学习SCALA的过程中,我遇到了SBT(Simple Build ...

  6. Samba 源码解析之内存管理

    由于工作需要想研究下Samba的源码,下载后发现目录结构还是很清晰的.一般大家可能会对source3和source4文件夹比较疑惑.这两个文件夹针对的是Samba主版本号,所以你可以暂时先看一个.这里 ...

  7. Table.Range保留中间指定的….Range/Middle(Power Query 之 M 语言)

    数据源: "姓名""基数""个人比例""个人缴纳""公司比例""公司缴纳"&qu ...

  8. CF999A Mishka and Contest 题解

    Content 能力值为 \(k\) 的小 M 参加一次考试,考试一共有 \(n\) 道题目,每道题目的难度为 \(a_i\).小 M 会选择两头中的一道难度不超过他的能力值题目去做,每做完一道,这道 ...

  9. IIS部署,发布网站

    一.IIS部署 1.打开控制面板,选择 '程序' 2.程序和功能下,选择打开或关闭Windows功能 3.等待加载,选择Internet信息服务,勾选如下选项 在弹出的"windows功能& ...

  10. 跨域:The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed

    https://blog.csdn.net/q646926099/article/details/79082204 使用Ajax跨域请求资源,Nginx作为代理,出现:The 'Access-Cont ...