※はじめからはこちら
前回は作成済のボードの一覧画面を作りました。今回は、ボードの追加機能を実装します。
サーバサイドの実装
まずはボードを追加するAPIを作っていきます。
サービスレイヤーの実装
まずはボードを追加するメソッドを用意します。
@@ -3,3 +3,16 @@ from .models import Board
def get_board_list_by_owner(owner):
return Board.get_list_by_owner(owner=owner)
+
+
+def add_board(owner, board_name):
+ """
+ :param User owner:
+ :param str board_name:
+ :return:
+ """
+ board = Board.objects.create(
+ owner=owner,
+ name=board_name
+ )
+ return board
add_board
に作成者とボード名を渡すことでBoard
モデルを生成するようにします。
viewの実装
APIのためのViewを実装します。postで必要なパラメータを受け取ったらボードを生成するようにしますので、 BoardListApi
にpost
メソッドを追加します。
@@ -1,3 +1,5 @@
+import json
+
from django.http import JsonResponse
from django.views.generic import View
class BoardListApi(View):
def get(self, request):
"""
ボードの一覧を戻す
"""
board_list = []
for board in kanban_sv.get_board_list_by_owner(request.user):
board_list.append({
'id': board.id,
'name': board.name,
})
return JsonResponse({
'board_list': board_list,
})
+ def post(self, request):
+ """
+ 新しいボードを追加する
+ """
+ data = json.loads(request.body)
+ board_name = data.get('boardName')
+ board = kanban_sv.add_board(
+ owner=request.user,
+ board_name=board_name
+ )
+ return JsonResponse({
+ 'board_data': {
+ 'id': board.id,
+ 'name': board.name,
+ }
+ })
さて、これだけだと実行時にエラーが出ます。Djangoのデフォルトの設定ではCSRF対策が有効化されています。APIでCSRFを考慮するのは面倒なので、解除してしまいます。
@@ -1,11 +1,14 @@
import json
from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
+from django.utils.decorators import method_decorator
from django.views.generic import View
from modules.kanban import service as kanban_sv
+@method_decorator(csrf_exempt, name='dispatch')
class BoardListApi(View):
def get(self, request):
csrf_exempt
というデコレータをつけると、そのViewについてはCSRF対策が無効化されます。Djangoのクラスベースビューを使ってる場合は、method_decorator
を使う必要があるので上のようなコードになります。厳密には、get
やpost
に処理を引き渡すdispatch
というメソッドがデフォルトでは定義されており、そこにcsrf_exempt
を付与するというコードです。お作法のようなものです。
urls.pyに割当
今回は、urls.pyへの割当は不要です。前回定義した以下の割当があります。
path('api/boards/', login_required(BoardListApi.as_view())),
/api/boads
へのGETアクセスでボードの一覧を取得していました。今回は同じURLにPOSTアクセスしてボードを作るので、URL自体は増えないため、マッピングの追加は不要です。
クライアントサイドの実装
追加ボタンコンポーネントの作成
ボード一覧の最後に追加ボタンを用意したいと思います。デザインは揃えたいので、前回作成したBoardCard.vue
をもとにAddBoardCard.vue
を以下の様に作ります。
<template>
<a href="#">
<div class="card bg-dark text-white">
<div class="card-body">
<h5 class="card-title">Add Board(+)</h5>
</div>
</div>
</a>
</template>
<script>
export default {
name: 'AddBoardCard',
};
</script>
特に動きなどは何もまだ用意していないのでガワだけです。これをまずはHome画面に組み込みます。
@@ -5,6 +5,7 @@
:title="board.name"
:boardId="board.id"
:key="board.id" />
+ <AddBoardCard class='board-card col-3' />
</div>
</div>
</template>
@@ -12,6 +13,8 @@
<script>
import { createNamespacedHelpers } from 'vuex';
import BoardCard from './components/BoardCard.vue';
+import AddBoardCard from './components/AddBoardCard.vue';
+
const { mapState, mapActions } = createNamespacedHelpers('home');
@@ -19,6 +22,7 @@ export default {
name: 'home',
components: {
BoardCard,
+ AddBoardCard,
},
computed: {
...mapState([
これで以下のように追加ボタンが表示されるようになりました。
KanbanClientへの追加
ボード追加のAPIを使えるようにするため、KanbanClient
にaddBoard
メソッドを追加します。
@@ -54,6 +54,11 @@ class KanbanClient extends Client {
return response.data.boardList;
}
+ async addBoard({ boardName }) {
+ await this._post(`${this.baseUrl}/boards/`, {
+ boardName,
+ });
+ }
}
storeへの組み込み
StoreからaddBoard
を使えるようにします。
@@ -10,6 +10,10 @@ const actions = {
const boardList = await KanbanClient.getBoardList();
commit('setBoardList', { boardList });
},
+ async addBoard({ dispatch }, { boardName }) {
+ await KanbanClient.addBoard({ boardName });
+ dispatch('fetchBoardList');
+ },
};
stateを更新せず、ボードの追加が完了したらdispatch('fetchBoardList');
でfetchBoardList
アクションを呼び出し、ボード一覧の再取得をするようにしています。
コンポーネントへの組み込み
先程作成した、AddBoardCard.vue
に組み込みます。
@@ -1,5 +1,5 @@
<template>
- <a href="#">
+ <a href="#" @click="addBoardAction">
<div class="card bg-dark text-white">
<div class="card-body">
<h5 class="card-title">Add Board(+)</h5>
@@ -9,7 +9,23 @@
</template>
<script>
+import { createNamespacedHelpers } from 'vuex';
+
+const { mapActions } = createNamespacedHelpers('home');
+
+
export default {
name: 'AddBoardCard',
+ methods: {
+ addBoardAction() {
+ const boardName = window.prompt('BoardName?');
+ if (boardName) {
+ this.addBoard({
+ boardName,
+ });
+ }
+ },
+ ...mapActions(['addBoard']),
+ },
};
</script>
@click="addBoardAction"
でこのコンポーネント自体がクリックされた際に、methods
に定義しているaddBoardAction
を呼び出すようにしました。この中では、ボード名の入力を促し、受け付けた後は先程Storeに定義したaddBoard
を呼び出しています。
これでボードの作成機能は実装完了です。以下のようにボードが追加できる様になっているはずです。
次回