DjangoとVue.jsでシンプルなTodoアプリを作る 07.VueでTodo作成機能を実装する
前回の記事ではVueでタスクを取得する方法について書きました。
続いて、タスクを作成する機能を Vue で作っていこうと思います。
一覧を取得するのとほとんど同じ流れで、下記の流れでコードを書いていきます。
html→Vue に task のタイトルを送れるようにする
Vue で task を作成する createTask メソッドを定義
html→Vue で送られてきた新しい task の内容を django の views.py に送る
送られてきた内容を元に、task を作成し、db に保存する。
保存できたら、その結果(レスポンス)を Vue に返す。
html に新しい task が表示されていれば ok!
1.html から vue に task のタイトルを送れるように、準備します。
先程コメントアウトした、タスク追加フォームのコメントアウトを外し、以下のように修正してください。
task/templates/task_list.html
{% extends 'base.html' %}
{% block content %}
<div id="app">
{# 追加 #}
<form @submit.prevent="createTask">
<div class="form-group row">
<div class="col-9">
{# 追加 #}
<input type="text" class="form-control" v-model="task.title" placeholder="卵を買う">
</div>
<div class="col-3">
<button type="submit" class="btn btn-primary mt-auto">タスクを追加</button>
</div>
</div>
</form>
@submit.prevent="createTask"とは、form 内で submit したときに、createTask メソッドを呼び出すという意味です。
今回の場合は、タスクを追加ボタンを押すと、createTask メソッドが実行されます。
v-model="task.title"とは、vue の main.js でこれから定義する、data 変数の task.title に入力した値を代入するという意味です。
例えば、html のテキストフォームにタイトルを「あ」と入力すると、vue の data 変数の task.title の値が html で入力した「あ」という文字に置き換わります。
2.Vue で task を作成する createTask メソッドを getTasks()のあとに定義します。
data()の中に先程 html で、v-model="task.title"と書いた、task.title を保存する変数も定義します。
const App = {
data() {
return {
// 追加
task: {title: ''},
tasks: [],
}
},
compilerOptions: {
delimiters: ['[[', ']]'],
},
methods: {
getTasks(){
fetch(URL, {
method: 'get',
//略
},
// 追加
createTask(){
// csrfトークンを定義
const csrftoken = Cookies.get('csrftoken');
// taskリストを取得する
this.getTasks();
fetch(URL, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
// htmlから入力されたtaskの情報をviews.pyに送信
body:JSON.stringify(this.task),
})
.then((response) => {
return response.json();
})
.then((task) => {
console.log(task)
// タイトルを空にする
this.task.title = ''
this.getTasks();
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
},
},
created() {
this.getTasks();
},
書いたコードの説明をします。
はじめに、getTask メソッドと違い、createTask メソッドは、データを django の views.py に送る際に、csrf トークンを付与しなければいけません。
csrf_token とは、CSRF(クロスサイトリクエストフォージェリ)を検証する仕組みで、データを変更するときには、必ず記述する必要があります。
html からデータを送信する際は、django のテンプレートタグである、{% csrf_token %}を記述すれば大丈夫でした。
ですが、今回は Vue からデータを送信する必要があります。その場合はどうすればいいでしょうか。
Django のドキュメントをみると、ajax を使用した際に、どうやって、csrf トークンを付与すればいいかが書いてあります。
今回は、下記ドキュメントにかいてある、JavaScript Cookie library を使用して、csrf トークンを付与します。
設定は簡単で、base.html に、JavaScript Cookie library の cdn を追加します。
</div>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
{# 追加 #}
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.0/dist/js.cookie.min.js"></script>
<script src="{% static 'main.js' %}"></script>
</body>
</html>
main.js にconst csrftoken = Cookies.get('csrftoken');と定義し、
下記のように headers に追加すれば問題ありません。
createTask(){
const csrftoken = Cookies.get('csrftoken');
this.getTasks();
fetch(URL, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
続いて、fetch する内容について、解説します。
html から vue に新たに作りたい task のタイトルを受け渡したいと思います。
その場合は、新たに body を定義し、そこに html で送信したデータを定義します。
JSON.stringify とは、json のオブジェクトを json 文字列に変換し、vue から django に送信できる形に変更するメソッドです。
fetch(URL, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
// htmlから入力されたtaskの情報をviews.pyに送信
body:JSON.stringify(this.task),
})
送信したあと、Vue の data にあるtask: {title: ''}を空にし、task のリストを再取得する処理を入れてください。
.then((response) => {
return response.json();
})
.then((task) => {
console.log(task)
// タイトルを空にする
this.task.title = ''
this.getTasks();
})
これをしないと、html に何を入力しても前送信した task の title が残って、同じ task を追加し続けてしまいます。
また、リストを再取得しないと、task を追加したはずなのに、反映されないということが起こるので注意してください。
vue の方のコードが書き終わったので、django の views.py も書いていきます。
post メソッドを下記の様に書き直してください。
def post(self, request):
# json文字列を辞書型にし、pythonで扱えるようにする。
task = json.loads(request.body)
form = TaskForm(task)
# データが正しければ保存する。
if form.is_valid():
new_task = form.save()
return JsonResponse({"task": model_to_dict(new_task)}, status=200)
return redirect("task_list_url")
はじめに、vue から送信した json データを python で扱えるように辞書型に変更します。
json.loads というメソッドを使うと変更することが可能です。
次に、html→django にデータを送信したときと同じように、TaskForm を使用して、task を保存します。
保存できたら、保存したデータを vue に返します。
ここで出てきた model_to_dict は、下記のように、django の model のデータを辞書型に変更してくれるメソッドです。
{'id': 8, 'title': 'e', 'completed': False}
こうすることで、django→vue にデータを送信することができます。
完了したら、タスクを追加からタスクを追加できるか確認しましょう。
追加できたら今回の機能は完成です。お疲れさまでした!
今回の記事ではVueでTodo作成機能を実装しました。次回の記事では、VueでTodoデータを更新できるようにします!
おまけ記事
⏩webサービスの作り方が気になったら
⏩Djanogを学ぶメリットについてはこちら
この記事が気に入ったらサポートをしてみませんか?