はじめに
前回作ったこちらの環境を用いて、タスク管理アプリ的なものを作成していきたいと思います。
タスクのモデルを作成(Flask)
まずはこちらのサイトを参考に、タスクのクラスを作成し一通りFlask側のみで動作するところまでを作成いたします。
2. Flaskチュートリアル
前回からのファイル構成変更点
その前に、前回作成した構成を若干修正します。
前回は下記の構成だったかと思いますが、今後の扱いやすさを考慮しファイル名とその中の記載内容を変更します。
app_dir ┣appserver.py → manage.pyにファイル名変更 ┣frontend/ ┗backend/ ┣api.py ┣application.py → __init__.pyにファイル名変更 ┗config.py
それぞれファイル名を変更したものの中身は以下です。
# __init__.py(←application.py) from flask import Flask from flask_cors import CORS app = Flask('FLASK-VUE', static_folder = "./dist/static", template_folder = "./dist") app.config.from_object('backend.config.BaseConfig') from backend.api import api app.register_blueprint(api, url_prefix="/api") cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) @app.route('/', defaults={'path': ''}) @app.route('/<path:path>') def catch_all(path): if app.debug: return requests.get('http://localhost:8080/{}'.format(path)).text return render_template("index.html")
# maange.py (←appserver.py) from backend import app if __name__ == '__main__': app.run()
sqliteを使用する設定
チュートリアルに倣い、sqliteはSQLAlchemyで操作します。
まずは以下コマンドでインストールします。
Flask-SQLAlchemyのインストール
$ pip install Flask-SQLAlchemy
次にconfig.py
を編集します.
# config.py import os class BaseConfig(object): DEBUG = True ## 以下を追記 SQLALCHEMY_DATABASE_URI = 'sqlite:///backend.db' # cookieを暗号化する秘密鍵 SECRET_KEY = os.urandom(24)
# __init__py from flask import Flask from flask_cors import CORS import requests from flask_sqlalchemy import SQLAlchemy # ここを追記 app = Flask('FLASK-VUE', static_folder = "./dist/static", template_folder = "./dist") app.config.from_object('backend.config.BaseConfig') db = SQLAlchemy(app) # ここを追記 from backend.api import api app.register_blueprint(api, url_prefix="/api") cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) @app.route('/', defaults={'path': ''}) @app.route('/<path:path>') def catch_all(path): if app.debug: return requests.get('http://localhost:8080/{}'.format(path)).text return render_template("index.html")
models.pyの作成
チュートリアルに倣い、以下のように記述します。
# backend/models.py from backend import db class Task(db.Model): __tablename__ = 'tasks' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.Text) text = db.Column(db.Text) def to_dict(self): return dict( id=self.id, title=self.title, text=self.text ) def __repr__(self): return '<Task id={id} title={title!r}>'.format( id=self.id, title=self.title) def init(): db.create_all()
コマンドラインからデータベースを初期化します。
$ python >>> from backend.models import init >>> init()
テータを登録してみます。
$ python >>> from backend.models import Task, db >>> Task.query.all() [] >>> task = Task(title='title', text='text') >>> db.session.add(task) >>> db.session.commit() >>> Task.query.all() [<Task id=1 title=u'title'>] >>> task = Task.query.get(1) >>> task <Task id=1 title=u'title'> >>> task.title = 'hello' >>> task.text = 'Hello world' >>> db.session.add(task) >>> db.session.commit() >>> Task.query.all() [<Task id=1 title=u'hello'>]
APIの作成(Flask)
まずはFlask側で登録のAPIを作成します。
基本は先程のチュートリアルを参考にしつつ、以下のように記述します。
# backend/api.py from flask import Blueprint, jsonify, request, url_for, make_response from random import * from flask_cors import CORS from backend import app, db from backend.models import Task api = Blueprint('api', __name__) @api.route('/hello/<string:name>/') def say_hello(name): response = { 'msg': "Hello {}".format(name) } return jsonify(response) @api.route('/random') def random_number(): response = { 'randomNumber': randint(1, 100) } return jsonify(response) @api.route('/get', methods=['GET']) def get_taks(): taks = Task.query.order_by(Task.id.desc()).all() taks_dict = [task.to_dict() for task in taks] return jsonify(taks_dict) @api.route('/add', methods=['POST']) def add_task(): task = Task( title=request.form['title'], text=request.form['text'] ) db.session.add(task) db.session.commit() task = Task.query.order_by(Task.id.desc()).first() id = str(task.id) r = make_response(id) return r @api.route('/delete', methods=['POST']) def delete_task(): id=request.form['id'] task = Task.query.get(id) db.session.delete(task) db.session.commit() r = make_response(id) return r
http://127.0.0.1:5000/api/get
にアクセスして、以下のようにレスポンスが返却されればOKです。
[ { "id": 1, "text": "Hello world", "title": "hello" } ]
登録画面の作成(Vue.js)
ルーティングの追加
続いて、Vue.jsのSPA側で、タスクの登録と閲覧をする画面を作成します。
$ cd frontend/src/component $ cp Home.vue Tasks.vue
また、SPA側のルーティングにもタスク画面を表示するように記述します。
// frontend/src/router/index.js /////// 省略 /////// const routerOptions = [ { path: '/', component: 'Home' }, { path: '/about', component: 'About' }, { path: '/tasks', component: 'Tasks' },//ここを追記 { path: '*', component: 'NotFound' } ] /////// 省略 ///////
bootstrap-vueの導入
登録画面を作成するにあたってはbootstrap-vueを使用したいと思います。
公式サイトに記載されている通り、以下コマンドでインストールします。
$ npm install jquery $ npm install bootstrap-vue
また、こちらも記載されている通り、frontend/src/main.js
とfrontend/src/App.vue
に以下の記述を記載します。
// frontend/src/main.js import Vue from 'vue' import BootstrapVue from 'bootstrap-vue' //ここを追記 import App from './App' import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, render: h => h(App) }) Vue.use(BootstrapVue) //ここを追記
// frontend/src/App.vue /////// 省略 /////// <script> import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' export default { name: 'App' } </script> /////// 省略 ///////
画面の作成
そして、Tasks.vue
にて先程作成したバックエンド側のAPIを叩き、UIに表示するviewを作成します。
デザインは適当です笑。
// frontend/src/component/Task.vue <template> <div class="container"> <div align="center"> <div class="col-sm-8 col-md-6 col-lg-6"> <p>タスクの登録</p> <b-form v-if="show"> <b-form-group label="Title:" label-for="title"> <b-form-input id="title" type="text" required placeholder="Enter title"> </b-form-input> </b-form-group> <b-form-group label="Text:" label-for="title"> <b-form-textarea id="text" placeholder="Enter something" :rows="3" :max-rows="6"> </b-form-textarea> </b-form-group> <div align="center"> <div class="col-sm-4 col-md-2 col-lg-2"> <b-button block @click="addTask" variant="success">Add</b-button> </div> </div> </b-form> </div> </div> <b-list-group v-for="(task, index) in tasks" :key='index'> <b-list-group-item> {{ task.title }}<br> {{ task.text }} <b-button v-bind:src="task.id" block @click="deleteTasks(index, task.id)">削除</b-button> </b-list-group-item> </b-list-group> </div> </template> <script> import axios from 'axios' export default { data () { return { randomNumber: 0, tasks: [], show: true } }, methods: { getTasks () { const path = 'http://localhost:5000/api/get' axios.get(path) .then(response => { this.tasks = response.data }) .catch(error => { console.log(error) }) }, addTask () { const path = 'http://localhost:5000/api/add' var title = document.getElementById('title') var text = document.getElementById('text') let params = new URLSearchParams() params.append('title', title.value) params.append('text', text.value) var titleValue = title.value var textValue = text.value title.value = '' text.value = '' axios.post(path, params) .then(response => { var id = response.data var task = {'id': id, 'text': textValue, 'title': titleValue} this.tasks.unshift(task) console.log(response) }) .catch(error => { console.log(error) }) }, deleteTasks (taskIndex, taskId) { console.log(taskIndex) console.log(taskId) const path = 'http://localhost:5000/api/delete' let params = new URLSearchParams() params.append('id', taskId) this.tasks.splice(taskIndex, 1) axios.post(path, params) .then(response => { console.log(response) }) .catch(error => { console.log(error) }) } }, created () { this.getTasks() } } </script>
http://127.0.0.1:5000/tasks
を開けば以下のように登録と削除ができる画面が動作すると思います。
あまりタスク管理っぽくないですが。笑
終わりに
これで、バックエンドとフロントエンドの役割が明確なWebアプリを作成出来ました。
あとはバックエンドのFlaskでAPIを作成し、フロントエンドのVue.jsでUIを描画すればいろんなWebアプリが作れるようになります。
次回はこのWebアプリにログイン機能をつけたいと思います。