![見出し画像](https://assets.st-note.com/production/uploads/images/71972633/rectangle_large_type_2_ed7a96009787fe81fe7c1c6be6c4388f.png?width=1200)
DjangoとVue.jsでシンプルなTodoアプリを作る 06.VueでTodoデータを取得する
前回の記事では、django と HTML で、task を作成し、作成したものを一覧で表示することができるようになりました。
ですが、まだ 1 クリックで task を完了にさせたり、削除したりする機能はできていません。
ここからは、django と HTML のみで実装するのではなく、Vue.js を使用して、task の一覧を表示、作成、更新、削除を画面の遷移なしでできるようにしたいと思います。
static/main.js を作成し、Vue を使う準備をするために、下記を追加してください。
static/main.js
const App = {
data() {
return {
tasks: [],
}
},
compilerOptions: {
delimiters: ['[[', ']]'],
},
methods: {
},
created() {
},
}
Vue.createApp(App).mount('#app')
const App で定義された data は、今回のアプリで扱う task のデータを保存する箱のようなものです。
compilerOptions delimiters は、Vue で保存したデータを html に表示する時に使用する形式を指定するためのものです。
通常、Vue は{{}}を使って、データを表示するのですが
今回 django で{{}}を使ってしまっているので、Vue のデータは[[]]を使って表示します。
methods は、Vue で使用するメソッドを書く部分です。
Django の views.py で書いていたメソッドを変わりにここに記述していきます。
created()には Vue のオブジェクトが起動したときに実行される処理を書きます。
今回の例でいうと、task を削除したり更新した時に、必ず task の一覧を更新する必要があります。
そのため、created()の中に、task の一覧を更新する処理を書く必要があります。
最後の Vue.createApp(App).mount('#app')で、html の id=app の要素に、
この Vue のオブジェクトが作られるようになります。
具体的にどのように Vue を使って HTML にデータを表示するかイメージそ作るために、
試しに data に文字を入れてみます。
static/main.js
const App = {
data() {
return {
tasks: ['test'],
}
},
compilerOptions: {
delimiters: ['[[', ']]'],
},
methods: {
},
created() {
},
}
Vue.createApp(App).mount('#app')
Vue を有効にするために、div 要素に id="app"を追加してください。
また、[[tasks]]を記述してください。
task/templates/task_list.html
{% extends 'base.html' %}
{% block content %}
{# 追加 #}
<div id="app">
[[ tasks ]]
<form method="POST">
{% csrf_token %}
<div class="form-group row">
<div class="col-9">
{{ form.title }}
</div>
<div class="col-3">
<button type="submit" class="btn btn-primary mt-auto">タスクを追加</button>
</div>
</div>
</form>
<div class="mt-5">
<div class="card mb-2" v-for="task, index in tasks">
写真のように test が表示されたと思います。
![](https://assets.st-note.com/img/1644556772856-ESZIQHbVXZ.png?width=1200)
このように、<div id="app">で囲まれた中に、Vue で定義した data を[[]]でくくって記述すると、値が表示されることが確認できました。
なんとなく Vue の使い方がわかったところで、全 task を表示するために、Vue HTML Django を使って、task 一覧を取得するコードを書いていきたいと思います。
流れはこんな感じです。
Vue で task 一覧を取得する getTasks メソッドを定義
django の views.py にリクエストを送る
レスポンスを Vue に返す
html で結果を表示します。
まず、1 の、Vue で task の一覧を受け取る、getTasks メソッドを定義していきます。
static/main.js
methods: {
getTasks(){
fetch(URL, {
method: 'get',
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
return response.json();
})
.then((tasks_list) => {
this.tasks = tasks_list;
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
},
},
created() {
this.getTasks();
},
書いたコードについて説明します。
今回は、Fetch API の fetch()メソッド使って、Django の views.py から task の情報を持ってきています。
Fetch API とは?
JavaScript を使って、インターネット上でデータを取得できる機能です。
基本の構文はこのような形で、
fetch(url)
.then(response => response.json)
.then(data => console.log(data));
一行目に取得したい情報を提供している url を書き、
二行目に返ってきたレスポンスを 何形式で受け取るか指定し、
三行目で、レスポンスのデータの処理方法を定義します。
例えば、クジラ web api というものを使って、簡単に情報を取得してみます。
下記をコンソールに書き、実行すると
fetch('https://api.aoikujira.com/tenki/week.php?fmt=json&city=319')
.then(response => response.json())
.then(data => console.log(data));
一週間の天気の情報が、クジラ web api から取得できます!
0: {date: '22日(土)', forecast: '晴後曇', mintemp: '10', maxtemp: '10', poptimes: '-/-/-', …}
1: {date: '23日(日)', forecast: '晴時々曇', mintemp: '10', maxtemp: '10', poptimes: '-/-/-', …}
2: {date: '24日(月)', forecast: '晴時々曇', mintemp: '2', maxtemp: '11', poptimes: '-/-/-', …}
3: {date: '25日(火)', forecast: '曇', mintemp: '2', maxtemp: '8', poptimes: '-/-/-', …}
4: {date: '26日(水)', forecast: '曇', mintemp: '3', maxtemp: '11', poptimes: '-/-/-', …}
5: {date: '27日(木)', forecast: '晴時々曇', mintemp: '3', maxtemp: '11', poptimes: '-/-/-', …}
6: {date: '28日(金)', forecast: '晴時々曇', mintemp: '2', maxtemp: '9', poptimes: '-/-/-', …}
7: {date: '29日(土)', forecast: '晴時々曇', mintemp: '1', maxtemp: '8', popti
![](https://assets.st-note.com/img/1644556850061-SJ1enp5SDr.png)
このように、Fetch api の構文に沿って、コードを書くとデータを取得することができます。
脱線してしまいましたが、Django の views.py からデータを取得するにはどうすればいいでしょうか。
まず、取得元の url ですが、html 上に、script タグを定義し、そこから URL を指定するようにします。
task/templates/task_list.html
</div>
</div>\{# 追加 #}
<script>
const URL = '{% url "task_list" %}';
</script>
{% endblock %}
methods: {
getTasks(){
fetch(URL, {
method: 'get',
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
return response.json();
})
.then((tasks_list) => {
this.tasks = tasks_list;
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
},
},
created() {
this.getTasks();
},
先程のクジラ web api ではしていしませんでしたが、後々必要になるので、method と、headers も指定します。
まず method ですが、今回は一覧を取得するので get と指定します。
続いて headers に'Content-Type': 'application/json'と指定します。
views.py の get メソッドは、html 形式で情報を返す場合と、今回の json 形式で返す場合があります。
views.py でそれぞれの場合を切り分けたいので、このように Content-Type を指定します。
続いて、2 の django の views.py にリクエストを送る処理をしていきます。
views.py を下記のように書き換えてください。
class TaskView(View):
def get(self, request):
# リクエストがjson形式のとき
if request.headers.get("Content-Type") == "application/json":
# すべてのtaskを辞書型で受け取る
tasks = Task.objects.values()
tasks_list = list(tasks)
# json形式でレスポンスを返す
return JsonResponse(tasks_list, safe=False, status=200)
return render(request, "task_list.html")
コメントで書いたように、リクエストが json 形式の場合、すべての task を辞書型にした値をリストにし、それを json 形式でリクエストもとに返す処理をしています。
実際に js に返すデータは下記のような感じです。
[{'id': 4, 'title': 'ついか', 'created_at': datetime.date(2022, 1, 8), 'completed': False}, {'id': 3, 'title': 'a', 'created_at': datetime.date(2021, 12, 30), 'completed': False}, {'id': 1, 'title': '卵を買う', 'created_at': datetime.date(2021, 12, 29), 'completed': False}, {'id': 2, 'title': '新年の目標を立てる', 'created_at': datetime.date(2021, 12, 29), 'completed': False}]
最後に vue で受け取ったデータを html で表示していきます。
下記のように、html を書き換えてください。
{% extends 'base.html' %}
{% block content %}
<div id="app">
{# 一旦コメントアウト #}
{% comment %} <form method="POST">
{% csrf_token %}
<div class="form-group row">
<div class="col-9">
{{ form.title }}
</div>
<div class="col-3">
<button type="submit" class="btn btn-primary mt-auto">タスクを追加</button>
</div>
</div>
</form> {% endcomment %}
<div class="mt-5">
{# 追加 #}
<div class="card mb-2" v-for="task, index in tasks">
<div class="card-body">
<div class="form-check">
<input class="form-check-input" type="checkbox" />
<label class="form-check-label">
{# 追加 #}
[[ task.title ]]
</label>
<button type="button" class="close float-right">
<span>×</span>
</button>
</div>
</div>
</div>
</div>
</div>
<script>
const URL = '{% url "task_list" %}';
</script>
{% endblock %}
div 要素に、v-for を追加します。
v-for は、Vue でいう django の for 文と似たような役割で、複数ある task を順番に並べてくれます。
task.title で、task のタイトルを表示します。
写真のように、一覧が表示されれば ok です!
![](https://assets.st-note.com/img/1644556906278-KxLVjTHPvn.png?width=1200)
今回の記事では、VueでTodoデータを取得する方法を紹介しました。
次回の記事ではVueでTodo作成機能を実装する方法を紹介します。
おまけ記事
⏩webサービスの作り方が気になったら
⏩Djanogを学ぶメリットについてはこちら