DjangoでToDoリストを作ってみる

## はじめに
初めまして。
こちらの記事ではDjangoでToDoリストを開発するテーマで記載しています。
Django初心者向けになります。

## Django（ジャンゴ）とは
DjangoはPythonプログラミング言語で書かれたオープンソースのウェブアプリケーションフレームワークです。Djangoは高い生産性と効率を提供し、ウェブ開発者が迅速に安定したウェブアプリケーションを構築できるようにすることを目的としています。

**Python（パイソン）とは**
Pythonは汎用の高水準なプログラミング言語で、シンプルで読みやすい構文が特徴です。
Pythonは機械学習、データ分析、ウェブ開発、自動化、科学計算、ネットワークプログラミングなど、多岐にわたる用途で使用されています。

## Djangoの特徴
Djangoは広く使われ、多くの大規模なウェブアプリケーションやウェブサイトで採用されています。
Djangoフレームワークは以下の特徴があります。

**ORM（Object-Relational Mapping）**
DjangoはORMを提供し、データベースとの対話をPythonコードで行えるようにします。これにより、SQLクエリを直接書かなくてもデータベースとのやり取りができます。

**管理画面**
Djangoには管理画面が組み込まれており、データベースの管理やコンテンツの編集などが容易に行えます。

**セキュリティ機能**
Djangoはセキュリティを重視しており、クロスサイトスクリプティング（XSS）、クロスサイトリクエストフォージェリ（CSRF）などのセキュリティ攻撃から保護されています。

**URLルーティング**
URLパターンを使用して、どのビューが特定のURLに対応するかを定義できます。

**フォームとバリデーション**
フォームの作成とデータのバリデーションが簡単に行えます。

## MVT（Model-View-Template）
Djangoフレームワークで使用されるウェブ開発のアーキテクチャパターンです。DjangoはMVTアーキテクチャを採用しており、MVTの構成要素は次の通りになります。

**Model（モデル）**
データベースやデータの取得・保存・処理などを担当します。
アプリケーションのデータ構造やビジネスロジックがモデルに定義されます。
DjangoではモデルはORM（Object-Relational Mapping）を用いてデータベースとやり取りします。

**View（ビュー）**
ユーザーのリクエストを受け取り、モデルからデータを取得してテンプレートに渡すなど、ビジネスロジックの制御をしています。
MVTではビューがコントローラの役割もしています。
ビューはユーザーに対して表示するデータを持たず、データはモデルから連携されます。

**Template（テンプレート）**
ユーザーに表示されるHTML文書を生成しています。
ユーザーに対して可視な部分であり、ウェブページの構造やデザインが定義されています。

## 開発環境の設定
ToDoリストを作成するために以下の手順で、開発環境を設定しておきましょう。

### 開発ツールをインストール
Pythonでは、主に以下の開発ツールが使用されています。
・Visual Studio Code (VSCode)
・PyCharm
・Atom

ご自身が使いやすい開発ツールを使用してください。

### Pythonをインストール
以下のサイトから最新のバージョンをダウンロードします。

https://www.python.org/downloads/

Pythonのインストール手順は以下のサイトを参考にしてください。

https://www.javadrive.jp/python/install/index1.html

## DjangoでToDoリストを作成する
### ToDoリストの階層構造
ToDoリストの完成した場合の階層構造は以下になります。

```bash:階層構造
todo_project/              # プロジェクトのルートディレクトリ
|-- todo_project/          # プロジェクトの設定やルーティングを行うディレクトリ
|   |-- __init__.py
|   |-- asgi.py
|   |-- settings.py
|   |-- urls.py
|   |-- wsgi.py
|-- todo/                  # Todoリストのディレクトリ
|   |-- migrations/        # マイグレーションファイルが生成されるディレクトリ
|   |   |-- __init__.py
|   |-- __init__.py
|   |-- admin.py           # 管理者ページの設定
|   |-- apps.py            # アプリの設定
|   |-- forms.py           # フォームの定義
|   |-- models.py          # データベースモデルの定義
|   |-- tests.py           # テストのためのファイル
|   |-- urls.py            # アプリのルーティング
|   |-- views.py           # ビューの定義
|-- db.sqlite3             # データベースファイル（SQLiteを使用している場合）
|-- manage.py              # Djangoプロジェクトの管理コマンド
|-- requirements.txt       # プロジェクトの依存関係が記述されたファイル
|-- templates/             # HTMLテンプレートが格納されるディレクトリ	
|   |-- todo/              # アプリ別にテンプレートを保存することもある
|       |-- add_todo.html
|       |-- edit_todo.html
|       |-- todo_list.html
```

### Djangoのインストール
以下のコマンドを実行し、Djangoをインストールする。

```bash:bash
pip install Django
```

**pip(Pip Installs Packages)とは**
Pythonパッケージを管理するためのパッケージ管理システムです。
pip を使用すると、Pythonプロジェクトに必要な外部ライブラリやツールを容易にインストールできます。


### プロジェクトとアプリの作成
以下のコマンドを実行する。
Djangoプロジェクトとその中に含まれるアプリケーションを作成しています。
「todo_project 」はプロジェクトのルートディレクトリであり、「todo」 はそのプロジェクトに含まれるアプリケーションです。
アプリケーションは、プロジェクト内で機能ごとにモジュール化されます。
```bash:bash
django-admin startproject todo_project
cd todo_project
python manage.py startapp todo
```

### データベースの設定
Djangoプロジェクトの設定ファイルである settings.py でデータベースの設定を行っています。
ここでは、SQLite3を使用し、データベースファイルの名前を db.sqlite3 に指定しています。
todo_project/settings.py ファイルを開き、データベースの設定については、以下の内容で設定されていれば、特に変更は不要です。
    
```python:python
# todo_project/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / "db.sqlite3",
    }
}
```

**SQLite3とは**
SQLite3は、軽量でサーバーレスのデータベース管理システム（DBMS）です。SQLite3は、ファイルベースのデータベースエンジンであり、データベースが1つの単一のファイルに格納されます。

SQLite3は小規模なプロジェクトや開発、プロトタイプ作成などの用途に適しています。ただし、大規模なデータベースや高い同時アクセスが必要な場合、より大規模なデータベースエンジンを検討する必要があります。


### ToDoモデルの作成 (todo/models.py)
Todoアプリケーション内でデータベースモデルを作成しています。
ToDoItem モデルは、Todoアイテムの情報を表現するためのもので、「title」と「description」の2つの項目を持っています。
```python:python
# todo/models.py
from django.db import models

class ToDoItem(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.title
```

### ToDoビューの作成(todo/views.py)
ToDoアプリケーション内でビューを作成しています。
ビューは、ユーザーからのリクエストを受け取り、それに対する応答を返しています。
今回、ToDoのビューについては、以下の内容で設定をしています。

**ビューの説明**
todo_list ビュー：すべてのTodoアイテムを取得
add_todo ビュー：新しいToDoアイテムを追加
edit_todo ビュー：既存のToDoアイテムを編集
delete_todo ビュー：ToDoアイテムを削除

```python:python
# todo/views.py
from django.shortcuts import render, redirect
from .models import ToDoItem
from .forms import ToDoForm

# ToDoアイテムのリストを取得
def todo_list(request):
    todos = ToDoItem.objects.all()
    return render(request, 'todo/todo_list.html', {'todos': todos})

# ToDoアイテムを追加
def add_todo(request):
    if request.method == 'POST':
        form = ToDoForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('todo_list')
    else:
        form = ToDoForm()
    return render(request, 'todo/add_todo.html', {'form': form})

# 既存のToDoアイテムを編集
def edit_todo(request, todo_id):
    todo = ToDoItem.objects.get(pk=todo_id)
    if request.method == 'POST':
        form = ToDoForm(request.POST, instance=todo)
        if form.is_valid():
            form.save()
            return redirect('todo_list')
    else:
        form = ToDoForm(instance=todo)
    return render(request, 'todo/edit_todo.html', {'form': form, 'todo_id': todo_id})

# ToDoアイテムを削除
def delete_todo(request, todo_id):
    todo = ToDoItem.objects.get(pk=todo_id)
    todo.delete()
    return redirect('todo_list')
```


### ToDoリストのURLを設定(todo/urls.py)
ToDoリストのURLパターンを管理をしています。
ToDoリストの各機能に対応する URL パターンが定義され、それぞれのビュー関数が呼び出されるようになります。
例えば、「/add/」 にアクセスすると、「add_todo」ビューが呼び出され、新しい ToDo アイテムを追加するためのフォームが表示されます。

```python:python
# todo/urls.py
from django.urls import path
from .views import todo_list, add_todo, edit_todo, delete_todo

urlpatterns = [
    path('', todo_list, name='todo_list'),
    path('add/', add_todo, name='add_todo'),
    path('edit/<int:todo_id>/', edit_todo, name='edit_todo'),
    path('delete/<int:todo_id>/', delete_todo, name='delete_todo'),
]
```

### ToDoリストのURLをプロジェクトのURLに組み込む(todo_project/urls.py)
プロジェクトのルートURL設定にTodoアプリケーションのURLを組み込んでいます。
「/todo/」 以下のURLにアクセスするとTodoアプリケーション内のURL設定が適用されます。

```python:python
# todo_project/urls.py
from django.contrib import admin
from django.urls import path, include
from todo.views import todo_list  # Make sure todo_list is imported correctly

urlpatterns = [
    path('admin/', admin.site.urls),
    path('todo/', include('todo.urls')),
    path('', todo_list, name='home'),
]
```

### ToDoリストのHTMLテンプレート(todo/templates/todo/todo_list.html)
ToDoリストの表示に使用されるHTMLテンプレートを作成しています。
テンプレート内では、ToDoリストをループし、各ToDoアイテムを表示しています。
その際、各ToDoアイテムに編集と削除のリンクを追加しています。
また、新しいToDoアイテムを追加するためのリンクもあります。

```html:html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ToDoリスト</title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <!-- Custom styles for female-oriented design -->
    <style>
        body {
            background-color: #f0f8ff; /* AliceBlue */
        }

        .container {
            background-color: #ffffff; /* White */
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            margin-top: 20px;
        }

        .btn-info {
            background-color: #87cefa; /* LightSkyBlue */
            border-color: #87cefa; /* LightSkyBlue */
        }

        .btn-info:hover {
            background-color: #add8e6; /* LightBlue */
            border-color: #add8e6; /* LightBlue */
        }

        .btn-danger {
            background-color: #ff6347; /* Tomato */
            border-color: #ff6347; /* Tomato */
        }

        .btn-danger:hover {
            background-color: #ff4500; /* OrangeRed */
            border-color: #ff4500; /* OrangeRed */
        }
        /* Add more styles as needed */
    </style>
</head>

<body>
    <div class="container mt-4">
        <h2 class="mb-4">ToDoリスト</h2>
        <ul class="list-group mt-3">
            {% for todo in todos %}
            <li class="list-group-item d-flex justify-content-between align-items-center">
                {{ todo.title }}
                <span>
                    <a href="{% url 'edit_todo' todo.id %}" class="btn btn-info btn-sm mr-2">編集</a>
                    <a href="{% url 'delete_todo' todo.id %}" class="btn btn-danger btn-sm">削除</a>
                </span>
            </li>
            {% endfor %}
        </ul>
        <a href="{% url 'add_todo' %}" class="btn btn-primary mt-3">新しいToDoを追加</a>
    </div>
    <!-- Bootstrap JS and dependencies -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>

</html>
```

### ToDo追加のHTMLテンプレート(todo/templates/todo/add_todo.html)
新しい ToDo アイテムを追加するためのHTMLテンプレートを作成しています。
フォームを使用してタイトルを追加できるようにし、追加ボタンをクリックすると内容が保存され、Todoリストにリダイレクトされます。

```html:html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新しいToDoを追加</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body {
            background-color: #f0f8ff; /* AliceBlue */
        }
        .container {
            background-color: #ffffff; /* White */
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            margin-top: 20px;
        }
        .btn-primary {
            background-color: #00bfff; /* DeepSkyBlue */
            border-color: #00bfff; /* DeepSkyBlue */
        }
        .btn-primary:hover {
            background-color: #00acee; /* DodgerBlue */
            border-color: #00acee; /* DodgerBlue */
        }
        .btn-secondary {
            background-color: #87ceeb; /* SkyBlue */
            border-color: #87ceeb; /* SkyBlue */
        }
        .btn-secondary:hover {
            background-color: #5f9ea0; /* CadetBlue */
            border-color: #5f9ea0; /* CadetBlue */
        }
    </style>
</head>
<body>
  <div class="container mt-4">
    <h2 class="mb-4">新しいToDoを追加</h2>
    <form method="post" action="{% url 'add_todo' %}" class="mt-3">
      {% csrf_token %}
      <div class="form-group">
        <label for="{{ form.title.id_for_label }}">タイトル</label>
        {{ form.title }}
      </div>
      <div class="form-group">
        <label for="{{ form.description.id_for_label }}">詳細</label>
        {{ form.description }}
      </div>
      <button type="submit" class="btn btn-primary">追加</button>
      <a href="{% url 'todo_list' %}" class="btn btn-secondary">キャンセル</a>
    </form>
  </div>
  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
```

### ToDo編集のHTMLテンプレート(todo/templates/todo/edit_todo.html)
Todoアイテムを編集するためのHTMLテンプレートを作成しています。
フォームを使用してタイトルを編集できるようにし、保存ボタンをクリックすると内容が保存され、Todoリストにリダイレクトされます。

```html:html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ToDoを編集</title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <!-- Custom styles for female-oriented design -->
    <style>
        body {
            background-color: #f0f8ff; /* AliceBlue */
        }
        .container {
            background-color: #ffffff; /* White */
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            margin-top: 20px;
        }
        .btn-primary {
            background-color: #00bfff; /* DeepSkyBlue */
            border-color: #00bfff; /* DeepSkyBlue */
        }
        .btn-primary:hover {
            background-color: #00acee; /* DodgerBlue */
            border-color: #00acee; /* DodgerBlue */
        }
        .btn-secondary {
            background-color: #87ceeb; /* SkyBlue */
            border-color: #87ceeb; /* SkyBlue */
        }
        .btn-secondary:hover {
            background-color: #5f9ea0; /* CadetBlue */
            border-color: #5f9ea0; /* CadetBlue */
        }
    </style>
</head>
<body>
  <div class="container mt-4">
    <h2 class="mb-4">ToDoを編集</h2>
    <form method="post" action="{% url 'edit_todo' todo_id %}" class="mt-3">
      {% csrf_token %}
      {{ form.as_p }}
      <button type="submit" class="btn btn-primary">保存</button>
      <a href="{% url 'todo_list' %}" class="btn btn-secondary">キャンセル</a>
    </form>
  </div>
  <!-- Bootstrap JS and dependencies -->
  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
```

## Djangoの開発サーバーを起動
コマンドプロンプト等で以下のコマンドを実行し、開発サーバを起動します。
```bash:bash
python manage.py runserver
```
サーバが正常に起動すると、コマンドプロンプトに次のようにメッセージが表示されます。
```bash:bash
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```

ブラウザを開き、以下のURLにアクセスします。
http://127.0.0.1:8000/

### 正常に起動した場合の画面
正常に起動した場合、以下のToDoリスト画面が表示されます。
![127.0.0.1_8000_todo_ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619683/cf402dd5-b05a-b57e-512f-bf46d6ab3e43.png)

サーバを終了する際にはコマンドプロンプト等でCtrl + Cを押下します。

## まとめ
今回、DjangoでToDoリストを作成してみましたが、ブログアプリケーションやポートフォリオサイトの作成も初心者の方にはおすすめされていますので、これからDjangoを勉強してみたい方は是非、挑戦してみてください。
最後まで読んで頂き、有難うございました。