LoginSignup
6
6

More than 3 years have passed since last update.

DjangoでTodoアプリを作る③タスク一覧ページの作成

Last updated at Posted at 2020-04-17

このチャプターでは、タスク一覧ページを作成していきます。

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

マイグレーションの実行

まず、タスクテーブルを作成していきます。
タスクテーブルの定義は以下のようにします。

カラム論理名 カラム物理名
ID id
folderID folder_id
タイトル title
状態 status
作成日 created_at

これをもとにmodels.pyを編集していきます。以下のTaskモデルを追加します。

todo/models.py
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の部分です。

todo/models.py
STATUS_CHOICES = [(1, '未完了'),(2, '作業中'),(3, '完了')]

status = models.IntegerField(choices=STATUS_CHOICES, default=1)

statusをIntergerFieldに設定しますが、defaultの値として1を設定しています。
タスクを作成した最初の状態は必ず「未完了」の状態なので、何も指定しないときは「1」が入るようにしています。
また、choicesオプションによって、整数に未完了、作業中、完了を振り分けています。

2つめはfolder_idの部分です。

todo/models.py
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に関する項目が出てきていません。

Screenshot from 2020-04-17 10-48-48.png

Taskモデルを表示するには、admin.pyでTaskモデルをインポートする必要があります。以下のようにadmin.pyに追記します。

todo/aadmin.py
from django.contrib import admin
from .models import Folder, Task#追加

admin.site.register(Folder)
admin.site.register(Task)#追加

もう一度adminサイトにアクセスしてみると、下の画像のようにFoldersの下にTasksの項目が追加されていると思います。

Screenshot from 2020-04-17 10-51-55.png

ここでも、管理サイト上でいくつかタスクを追加しておきましょう。

Viewを書く

views.pyを以下のように編集します。

todo/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関数をインポートします。
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エラーとなります。
Screenshot from 2020-04-17 11-03-21.png

次に、この部分について。

tasks = Task.objects.filter(folder_id = current_folder.id)

ここでは、filter関数を用いてタスクのfolder_idが、選ばれたフォルダのidと等しいようなタスクをすべて取得し、tasksに代入しています。

テンプレートの編集

タスク一覧を表示するために、templates/index.html<!-- タスクはここに表示される -->とコメントが書かれていたところに以下のコードを挿入してください。

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です!

Screenshot from 2020-04-17 11-11-36.png

おわりに

これで、タスクを一覧表示することができました!
ここまでのコードは、リポジトリのchapter3ブランチにあります。
次は、フォルダー作成機能を実装していきます!

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

6
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6