このチャプターでは、タスク一覧ページを作成していきます。
##記事一覧
DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成
#マイグレーションの実行
まず、タスクテーブルを作成していきます。
タスクテーブルの定義は以下のようにします。
カラム論理名 | カラム物理名 |
---|---|
ID | id |
folderID | folder_id |
タイトル | title |
状態 | status |
作成日 | created_at |
これをもとにmodels.py
を編集していきます。以下のTaskモデルを追加します。
class Task(models.Model):
STATUS_CHOICES = [(1, '未完了'),(2, '作業中'),(3, '完了')]
title = models.CharField(max_length=100)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
due_date = models.DateField(default=timezone.now)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(blank=True, null=True)
folder_id = models.ForeignKey(Folder, on_delete = models.CASCADE)
def publish(self):
self.update_at = timezone.now()
self.save()
def __str__(self):
return self.title
ここでのポイントは2つ。
1つめは、status
の部分です。
STATUS_CHOICES = [(1, '未完了'),(2, '作業中'),(3, '完了')]
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
statusをIntergerFieldに設定しますが、defaultの値として1を設定しています。
タスクを作成した最初の状態は必ず「未完了」の状態なので、何も指定しないときは「1」が入るようにしています。
また、choicesオプションによって、整数に未完了、作業中、完了を振り分けています。
2つめはfolder_id
の部分です。
folder_id = models.ForeignKey(Folder, on_delete = models.CASCADE)
ForeignKeyによって、FolderモデルとTaskモデルを紐付けています。
on_delete=...の部分では、CASCADEを設定することによって削除するオブジェクトに紐づいたオブジェクトを全て削除することができます。こちらの記事が具体例が示されていてわかりやすいです。
(ちなみに、「cascade」は「何段も重なった小さな滝」という意味でありこれを覚えておくと、連なってオブジェクトが削除されることが理解しやすい)
ここまで来たら、makemigraions
でマイグレーションファイルを作ります。
次のコマンドを実行してください。
$ docker-compose run web python3 manage.py makemigrations
実行すると以下のようになり、todo/migrations
ディレクトリに新たにマイグレーションファイルが作成されます。
$ docker-compose run web python3 manage.py makemigrations
Starting django_todo_db_1 ... done
Migrations for 'todo':
todo/migrations/0002_task.py
- Create model Task
マイグレーションファイルを作成したので、次のコマンドを実行してマイグレートします。
$ docker-compose run web python3 manage.py migrate
実行すると以下のようになります。
docker-compose run web python3 manage.py migrate
Starting django_todo_db_1 ... done
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, todo
Running migrations:
Applying todo.0002_task... OK
#管理サイトの表示
マイグレートしたら、adminサイト( http://localhost:8000/admin/ )を確認してみましょう。
すると、TaskモデルをマイグレートしたはずなのにTaskに関する項目が出てきていません。
Taskモデルを表示するには、admin.pyでTaskモデルをインポートする必要があります。以下のようにadmin.pyに追記します。
from django.contrib import admin
from .models import Folder, Task#追加
admin.site.register(Folder)
admin.site.register(Task)#追加
もう一度adminサイトにアクセスしてみると、下の画像のようにFoldersの下にTasksの項目が追加されていると思います。
ここでも、管理サイト上でいくつかタスクを追加しておきましょう。
#Viewを書く
views.py
を以下のように編集します。
from django.shortcuts import render, get_object_or_404#追加
from django.utils import timezone
from .models import Folder, Task#追加
def index(request, id):
#すべてのフォルダを取得する
folders = Folder.objects.filter(created_at__lte=timezone.now()).order_by('created_at')
#選ばれたフォルダを取得する
current_folder = get_object_or_404(Folder, id=id)
#選ばれたフォルダのタスクを取得する
tasks = Task.objects.filter(folder_id = current_folder.id)
return render(request, 'index.html', {
'folders':folders,
'tasks':tasks,
'current_folder_id': current_folder.id,
})![Screenshot from 2020-04-17 11-03-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370196/2effc6d9-ccd6-3485-3eaa-4dceb2ae76da.png)
1行目で[get_object_or_404関数]
(https://docs.djangoproject.com/ja/3.0/topics/http/shortcuts/#get-object-or-404)をインポートします。
3行目では、models.py
で定義したTaskモデルをインポートしています。
get_object_or_404
関数では、Folderモデルにおけるpk(primary key)
、すなわちid
に一致するid
を受け取れば、id
に応じたオブジェクトがcurrent_folder
に代入されます。
Folderモデルのid
に存在しないid
を受け取ったときは404エラーを吐きます。
例えば、Folderが3つしか挿入されていないのに、http://localhost:8000/folders/5/tasks にアクセスすると以下のように404エラーとなります。
次に、この部分について。
tasks = Task.objects.filter(folder_id = current_folder.id)
ここでは、filter
関数を用いてタスクのfolder_id
が、選ばれたフォルダのid
と等しいようなタスクをすべて取得し、tasks
に代入しています。
#テンプレートの編集
タスク一覧を表示するために、templates/index.html
で<!-- タスクはここに表示される -->
とコメントが書かれていたところに以下のコードを挿入してください。
<div class="panel panel-default">
<div class="panel-heading">タスク</div>
<table class="table">
<thead>
<tr>
<th>タイトル</th>
<th>状態</th>
<th>期限</th>
<th></th>
</tr>
</thead>
<tbody>
{% for task in tasks %}
<tr>
<td>{{ task.title }}</td>
<td>
<span
class="label {% if task.status == 1 %}label-danger{% endif %}{% if task.status == 2 %}label-info{% endif %}"
>
{{ task.get_status_display }}
</span>
</td>
<td>{{ task.due_date }}</td>
<td><a href="#">編集</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="panel-body">
<div class="text-right">
<a href="#" class="btn btn-default btn-block">
タスクを追加する
</a>
</div>
</div>
</div>
注意するべきところは以下の部分だと思います。
<span
class="label {% if task.status == 1 %}label-danger{% endif %}{% if task.status == 2 %}label-info{% endif %}"
>
{{ task.get_status_display }}
</span>
choice属性で値を限定しているフィールドの「名前」を取得するには、get_status_displayメソッドを利用する必要があります。(get_status_displayメソッドは、勝手に定義されます。くわしくは、Djangoのモデルでchoice属性で値を限定しているフィールドの「名前」を取得する方法)
また、if文を使って、task.statusが1のとき、つまり未完了のときはlabel-danger
、task.statusが2のとき、つまり作業中のときはlabel-info
とクラスを割り当て、cssをタスクの状態ごとに適用させています。
ここまできたら、http://localhost:8000/folders/1/tasks にアクセスして確認してみてください!
以下のようになっていればOKです!
#おわりに
これで、タスクを一覧表示することができました!
ここまでのコードは、リポジトリのchapter3ブランチにあります。
次は、フォルダー作成機能を実装していきます!
##記事一覧
DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成