【Django】高速でTODOアプリを作成する


投稿日 2019年6月4日 >> 更新日 2023年3月3日

今回はDjangoフレームワークを使って高速でTODOアプリを作成したいと思います。上の図のようにTODOリストをカテゴリー分けを行える内容になります。

残念ながらカテゴリー・TODOリストの作成は既存のDjango管理画面にて行う事になりますが、削除機能は一覧画面にて行えるようにしています。

もし仮想環境下での作業をご希望の方がいましたら、こちらの記事を参照ください。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.8
pip 9.0.1
使用ライブラリ ライセンス
Django==2.2.6 BSD

Project作成〜Django管理画面にて要素を保存

Djangoのインストールが終わったらプロジェクトの作成をします。


$ django-admin startproject project

projectディレクトリに移動し、アプリケーションを作成します。


$ cd project

/project$ python3 manage.py startapp todo

アプリが作成されましたらprojectディレクトリ内のsettings.pyを編集します。

# /project/settings.py

INSTALLED_APPS = [
    'todo.apps.TodoConfig',  # ←アプリを追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
....
....
LANGUAGE_CODE = 'ja'  # ←編集
TIME_ZONE = 'Asia/Tokyo'  # ←編集

あと一回settings.pyに訪れますが、この時点でモデルを作成してしまいます。

アプリディレクトリ内のmodels.pyにてデータベースであるテーブルを作成します。

# /todo/models.py

from django.db import models


"""カテゴリー"""
class Category(models.Model):
    title = models.CharField('タイトル', max_length=20)

    """self.titleとすることでadmin管理画面にてインスタンス変数として表示される"""
    def __str__(self):
        return self.title


"""
タイトル、日付テーブルとカテゴリーを紐づけるためのテーブル。
PROTECTは紐づいているデータが存在すれば消されない
"""
class Todo(models.Model):
    title = models.CharField('タイトル', max_length=50)
    created_at = models.DateTimeField('日付', auto_now_add=True)
    category = models.ForeignKey(Category, on_delete=models.PROTECT)

    def __str__(self):
        return self.title

モデルで定義したテーブルをDjango管理画面にて表示させるようにadmin.pyを追記します。

# /todo/admin.py

from django.contrib import admin
from .models import Category, Todo


admin.site.register(Category)
admin.site.register(Todo)

ターミナルにてmanage.pyがあるディレクトリでモデルをデータベースへ適用させます。


/project$ python3 manage.py makemigrations
Migrations for 'todo':
  todo/migrations/0001_initial.py
    - Create model Category
    - Create model Todo

/project$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK

正しくモデルが定義されていれば上手く適用されます。

続けてDjango管理者の為のクリエイトスーパーユーザーコマンドで管理者登録も行います。


/project$ python3 manage.py createsuperuser
ユーザー名
アドレス
パスワード
確認パス

それではプロジェクトを起動してブラウザにてローカルサーバーを開きます。


/project$ python3 manage.py runserver
'http://127.0.0.1:8000'を開く

127.0.0.1:8000/adminと検索し管理画面を開きCategory、Todoの項目があればひとまず成功です。

カテゴリー、Todoに幾つかデータを保存できたらテンプレートまでを作成していきます。

View〜Templateで表示

データベースであるモデルを作成しデータを保存したので、あとは表示させるための記述をしていくだけです。

順番はproject下のurls.pyを編集しアプリ下にてurls.pyを新規作成、views.pyを編集しカテゴリーに使用するPythonファイルを作成し一旦settings.pyに戻って追記したらtemplateを作成して終了です。


project
|
|--project
|       |--urls.py
|       |--settings.py
|
|--todo
      |--urls.py
      |--views.py
      |--category_list.py
      |--templates
                |
                |--todo
                      |--base.html
                      |--index.html

プロジェクト下のurls.pyを編集します。

# /project/urls.py

from django.contrib import admin
from django.urls import path, include  # ←追記


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('todo.urls')),  # ←追記
]

アプリ下(todo)にてurls.pyを新規作成。

# /todo/urls.py

from django.urls import path
from . import views


app_name = 'todo'

urlpatterns = [
        path('', views.index, name='index'),  # ←一覧
        path('<int:id>/delete/', views.delete, name='delete'),  # ←削除機能用
        path('todo/<str:category>/', views.todo_category, name='todo_category'),  # ←カテゴリ
]

views.pyはURL、モデル、テンプレートへ引き渡しをする架け橋であります。

# /todo/views.py

from django.shortcuts import render, redirect, get_object_or_404
from .models import Todo, Category


"""一覧表示"""
def index(request):
    todo = Todo.objects.order_by('title')
    return render(request, 'todo/index.html', {'todo': todo})


"""削除機能"""
def delete(request, id):
    todo = get_object_or_404(Todo,pk=id)
    todo.delete()
    return redirect('todo:index')


"""カテゴリ"""
def todo_category(request, category):
    category = Category.objects.get(title=category)
    """カテゴリで絞り込む"""
    todo = Todo.objects.filter(category=category).order_by('title')
    return render(request, 'todo/index.html', {'todo': todo, 'category': category})

カテゴリのタイトルを取得するために新しくPythonファイルを作成。

# /todo/category_list.py

from .models import Category


def common(request):
    context = {
            'category_list': Category.objects.all(),
    }
    return context

作成したPythonファイルをsettings.pyに読み込ませる。

# /project/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'todo.category_list.common',  # ←追記
            ],
        },
    },
]

これで先ほど作成したcategory_list.pyファイル内の「category_list」をDjangoのテンプレートタグにて使用することができる。

あとはtemplatesディレクトリ・todoディレクトリ・base.html・index.htmlを作成するだけです。

templates/todo/にてベースとなるhtmlファイルを作成します。

<!-- /todo/templates/todo/base.html -->

<!doctype html>
<html>
    <head>

        <title>TODO</title>

    </head>
    <body>

        <h2>カテゴリー</h2>

        <ul>
            <a href="{% url 'todo:index' %}">
                <li>トップ</li>
            </a>
            {% for category in category_list %}
                <a href="{% url 'todo:todo_category' category %}">
                    <li>{{ category }}></li>
                </a>
            {% endfor %}
        </ul>

        {% block content %}
        {% endblock %}

    </body>
</html>

同じ配下に子テンプレートとなるindex.htmlを作成する。

<!-- /todo/templates/todo/index.html -->

{% extends 'todo/base.html' %}

{% block content %}

    <h2>TODOリスト</h2>

    {% if category %}
        <h2>カテゴリー: {{ category.title }}</h2>
    {% endif %}

    {% for todos in todo %}
        <ul>
            <li>{{ todos.title }}--{{ todos.created_at }}</li>
            <form method="POST" action="{% url 'todo:delete' todos.pk %}">
                {% csrf_token %}
                <button type="submit">削除</button>
            </form>   
        </ul>
    {% endfor %}

{% endblock %}

カテゴリーで絞り込むこともできます。

高速で終わらすためにも以上をもって終了したいと思います。

最後までご覧いただきありがとうございました。