flask 与 vue.js 2.0 实现 todo list
2017-03-22 21:49
716 查看
实现了后端与前端分离,后端提供 RESTful api。
后端 flask 与前端 vue 的数据传输都是 json。
本文使用 vue.js 2.0 对前一个例子:flask, SQLAlchemy, sqlite3 实现 RESTful API 的 todo list进行改写
为了避免jinja2 与 vue 同时使用 “{{ }}”而发生冲突,vue 的数据绑定使用 v-text
后端 flask 与前端 vue 的数据传输都是 json。
本文使用 vue.js 2.0 对前一个例子:flask, SQLAlchemy, sqlite3 实现 RESTful API 的 todo list进行改写
两个文件
from flask import Flask, jsonify, render_template from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db = SQLAlchemy(app) # 定义ORM class Todo(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(80), unique=True) description = db.Column(db.String(120), unique=True) done = db.Column(db.Boolean) def __init__(self, title, description, done): self.title = title self.description = description self.done = done def __repr__(self): return '<Todo %r>' % self.title # 创建表格、插入数据 @app.before_first_request def create_db(): # Recreate database each time for demo #db.drop_all() db.create_all() tasks = [Todo('Buy groceries', 'Milk, Cheese, Pizza, Fruit, Tylenol', False), Todo('Learn Python', 'Need to find a good Python tutorial on the web', False), Todo('Mow the lawn', 'Find out some tools', False)] db.session.add_all(tasks) db.session.commit() # ================================== # 下面是RESTful api # ================================== @app.route('/') def index(): return render_template('formdata_vue.html') # ================================== # 下面是RESTful api # ================================== # 辅助函数 from flask import url_for def replace_id_to_uri(task): return dict(uri = url_for('get_task', task_id=task.id, _external=True), title = task.title, description = task.description, done = task.done) # 查询全部 @app.route('/todo/api/v1.0/tasks/', methods=['GET']) def get_tasks(): tasks = Todo.query.all() return jsonify({'tasks': list(map(replace_id_to_uri, tasks))}) # 查询一个 from flask import abort @app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['GET']) def get_task(task_id): task = Todo.query.filter_by(id=task_id).first() if task is None: abort(404) return jsonify({'task': replace_id_to_uri(task)}) # 添加 from flask import request @app.route('/todo/api/v1.0/tasks/', methods=['POST']) def create_task(): # 没有数据,或者数据缺少 title 项,返回 400,表示请求无效 if not request.json or not 'title' in request.json: abort(400) task = Todo(request.json['title'], request.json.get('description', ""), False) db.session.add(task) db.session.commit() return jsonify({'task': replace_id_to_uri(task)}), 201 # 更新 @app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT']) def update_task(task_id): task = Todo.query.filter_by(id=task_id).first() if task is None: abort(404) if not request.json: abort(400) if 'title' in request.json and type(request.json['title']) != unicode: abort(400) if 'description' in request.json and type(request.json['description']) is not unicode: abort(400) if 'done' in request.json and type(request.json['done']) is not bool: abort(400) task['title'] = request.json.get('title', task['title']) task['description'] = request.json.get('description', task['description']) task['done'] = request.json.get('done', task['done']) #db.session.update(task) db.session.commit() return jsonify({'task': replace_id_to_uri(task)}) # 删除 @app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['DELETE']) def delete_task(task_id): task = Todo.query.filter_by(id=task_id).first() if task is None: abort(404) db.session.delete(task) db.session.commit() return jsonify({'result': True}) # 定制404出错页面 @app.errorhandler(404) def not_found(error): return jsonify({'error': 'Not found'}), 404 if __name__ == '__main__': app.run(debug=True)
为了避免jinja2 与 vue 同时使用 “{{ }}”而发生冲突,vue 的数据绑定使用 v-text
<meta charset="utf-8"/> <script src="{{ url_for('static', filename='js/vue.min.js') }}"></script> <!-- <script src="{{ url_for('static', filename='js/fetch.js') }}"></script> --> <div id="app"> <form v-on:submit="ajax"> <div class="form-group"> <input type="text" v-model="title" placeholder="任务标题" required="required"> </div> <div class="form-group"> <input type="texteara" v-model="description" placeholder="任务描述" required="required"> </div> <input type="submit" class="btn btn-default" value="添加任务"> </form> <!-- 任务列表 --> <ol> <li v-for="task in tasks"> <span v-text="task.title"></span> -- <span v-text="task.description"></span> -- <span v-text="task.done"></span> </li> </ol> </div> <script> var vm = new Vue({ el: '#app', data: { title: '', description: '', tasks: [ // { // uri: 'todo/api/v1.0/tasks/1', // title: 'waw the land', // description: 'do something best', // done: false // } ] }, // 事件钩子 beforeCreate: function () { // `this` 指向 vm 实例 var _this = this; //this只能到这一层 // 原生 js 实现 ajax var xhr = new XMLHttpRequest(); xhr.open('GET', '/todo/api/v1.0/tasks/'); xhr.send(); xhr.addEventListener('loadend', function() { if(xhr.status == 200){ var res = JSON.parse(xhr.responseText); console.log(res); res["tasks"].map(function(task){_this.tasks.push(task)}); } }, false); // fetch 库实现 ajax //fetch('/todo/api/v1.0/tasks/') //.then(r => r.json()) //.then(j => { // console.log(j); // this.tasks = j.tasks; //暴力替换 //}) }, methods: { ajax: function(event){ event.preventDefault(); var _this = this; //this只能到这一层 var payload = { title: _this.title, description: _this.description }; console.log(payload); // 原生 js 实现 ajax var xhr2 = new XMLHttpRequest(); xhr2.open('POST', '/todo/api/v1.0/tasks/'); xhr2.setRequestHeader('Content-Type', 'application/json'); xhr2.send(JSON.stringify(payload));// 发送json数据! xhr2.addEventListener('loadend', function() { if(xhr2.status == 201){ // 注意,这里是201,与后台一致!! var res2 = JSON.parse(xhr2.responseText); console.log(res2["task"]); //[res2["task"]].map(function(task){_this.tasks.push(task)}); // 这里也用map,没别的目的,只想与前面的形式一致 _this.tasks.push(res2["task"]); //动作温柔 } }, false); // fetch 库实现 ajax //fetch('/todo/api/v1.0/tasks/', { // method: 'POST', // headers: { // 'Content-Type': 'application/json' // }, // body: JSON.stringify(payload) //}) //.then(r => r.json()) //.then(j => { // console.log(j); //[j.task].map(function(task){_this.tasks.push(task)}); // _this.tasks.push(j.task); //动作温柔 //}) } } }); </script>
效果图
打开浏览器控制台相关文章推荐
- vue.js 实现 todo list 任务表单-2
- vue.js几行实现的简单的todo list
- vue.js 实现 todo list 任务表单
- flask, SQLAlchemy, sqlite3 实现 RESTful API 的 todo list, 同时支持form操作
- vue.js 学习笔记 制作简单的todo list
- [IMWeb训练营作业]vue实现简单的todo list
- Vue.js 第一发【 todo list (IMWeb训练营作业)】
- 用vue.js简单实现todo-list
- vue2.0 引用qrcode.js实现获取改变二维码的样式
- vue demo todo-list
- Vue.js实现一个todo-list的上移下移删除功能
- 基于 Vue.js 2.0 酷炫自适应背景视频登录页面实现方式
- vue2.0使用Sortable.js实现的拖拽功能
- Vue学习完成Todo List网页
- IMweb训练营作业—-Todo List(vue)
- vue.js2.0父子组件间传参 (一)实现弹窗
- flask + vue.js 实现简单todolist应用
- vue2.0使用Sortable.js实现的拖拽功能
- 【IMWeb训练营作业】第一次Vue作业-todo list
- Vue2.0 引用 exif.js 实现调用摄像头进行拍照功能以及图片上传功能