この記事では、Djangoを使用してシンプルなTODOアプリケーションを作成し、Renderにデプロイするまでの手順を解説します。
目次
- 開発環境のセットアップ
- Djangoプロジェクトの作成
- TODOアプリの実装
- ローカル環境での動作確認
- Renderへのデプロイ準備
- Renderへのデプロイ
- トラブルシューティング
- データベースについての補足
- その他の参考情報
1. 開発環境のセットアップ
仮想環境の作成と有効化
# 仮想環境の作成
python -m venv todo_env
# 仮想環境の有効化(macOS/Linux)
source todo_env/bin/activate
# 仮想環境の有効化(Windows)
# todo_env\Scripts\activate
必要なパッケージのインストール
pip install django
2. Djangoプロジェクトの作成
プロジェクトの作成
django-admin startproject todo_project
cd todo_project
アプリケーションの作成
python manage.py startapp todo_app
settings.pyの設定
todo_project/settings.py
にアプリケーションを追加します。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo_app', # 追加
]
# 言語と時間帯の設定
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
URLの設定
todo_project/urls.py
を編集して、TODOアプリのURLを設定します。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todo_app.urls')),
]
3. TODOアプリの実装
モデルの作成
todo_app/models.py
にTodoモデルを定義します。
from django.db import models
from django.utils import timezone
class Todo(models.Model):
STATUS_CHOICES = (
('未完了', '未完了'),
('進行中', '進行中'),
('完了', '完了'),
)
title = models.CharField('タイトル', max_length=100)
description = models.TextField('詳細', blank=True)
status = models.CharField('ステータス', max_length=10, choices=STATUS_CHOICES, default='未完了')
priority = models.IntegerField('優先度', default=0)
created_at = models.DateTimeField('作成日時', default=timezone.now)
updated_at = models.DateTimeField('更新日時', auto_now=True)
due_date = models.DateField('期限', null=True, blank=True)
def __str__(self):
return self.title
class Meta:
ordering = ['-priority', 'due_date', '-created_at']
verbose_name = 'Todo'
verbose_name_plural = 'Todos'
フォームの作成
todo_app/forms.py
を作成し、Todoモデル用のフォームを定義します。
from django import forms
from .models import Todo
class TodoForm(forms.ModelForm):
class Meta:
model = Todo
fields = ['title', 'description', 'status', 'priority', 'due_date']
widgets = {
'due_date': forms.DateInput(attrs={'type': 'date'}),
}
ビューの作成
todo_app/views.py
に必要なビューを実装します。
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib import messages
from .models import Todo
from .forms import TodoForm
class TodoListView(ListView):
model = Todo
template_name = 'todo_app/todo_list.html'
context_object_name = 'todos'
class TodoDetailView(DetailView):
model = Todo
template_name = 'todo_app/todo_detail.html'
context_object_name = 'todo'
class TodoCreateView(CreateView):
model = Todo
form_class = TodoForm
template_name = 'todo_app/todo_form.html'
success_url = reverse_lazy('todo_list')
def form_valid(self, form):
messages.success(self.request, 'タスクを作成しました。')
return super().form_valid(form)
class TodoUpdateView(UpdateView):
model = Todo
form_class = TodoForm
template_name = 'todo_app/todo_form.html'
success_url = reverse_lazy('todo_list')
def form_valid(self, form):
messages.success(self.request, 'タスクを更新しました。')
return super().form_valid(form)
class TodoDeleteView(DeleteView):
model = Todo
template_name = 'todo_app/todo_confirm_delete.html'
success_url = reverse_lazy('todo_list')
def delete(self, request, *args, **kwargs):
messages.success(self.request, 'タスクを削除しました。')
return super().delete(request, *args, **kwargs)
def change_status(request, pk):
todo = get_object_or_404(Todo, pk=pk)
if todo.status == '未完了':
todo.status = '進行中'
elif todo.status == '進行中':
todo.status = '完了'
else:
todo.status = '未完了'
todo.save()
messages.success(request, f'「{todo.title}」のステータスを「{todo.status}」に変更しました。')
return redirect('todo_list')
URLの設定
todo_app/urls.py
を作成し、ビューとURLのマッピングを定義します。
from django.urls import path
from . import views
urlpatterns = [
path('', views.TodoListView.as_view(), name='todo_list'),
path('todo/<int:pk>/', views.TodoDetailView.as_view(), name='todo_detail'),
path('todo/new/', views.TodoCreateView.as_view(), name='todo_new'),
path('todo/<int:pk>/edit/', views.TodoUpdateView.as_view(), name='todo_edit'),
path('todo/<int:pk>/delete/', views.TodoDeleteView.as_view(), name='todo_delete'),
path('todo/<int:pk>/change_status/', views.change_status, name='change_status'),
]
テンプレートの作成
テンプレートディレクトリとファイルを作成します。
mkdir -p todo_app/templates/todo_app
todo_app/templates/todo_app/base.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 href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
<header class="mb-4">
<h1><a href="{% url 'todo_list' %}" class="text-decoration-none">TODOアプリ</a></h1>
</header>
{% if messages %}
<div class="messages">
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
<main>
{% block content %}
{% endblock %}
</main>
<footer class="mt-5 text-center text-muted">
<p>Django TODO App</p>
</footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
その他必要なテンプレートファイル(リスト表示、詳細表示、フォーム、削除確認など)も作成します。
データベースのマイグレーション
python manage.py makemigrations
python manage.py migrate
管理サイトの設定
todo_app/admin.py
を編集して管理サイトにTodoモデルを登録します。
from django.contrib import admin
from .models import Todo
@admin.register(Todo)
class TodoAdmin(admin.ModelAdmin):
list_display = ('title', 'status', 'priority', 'due_date', 'created_at')
list_filter = ('status', 'priority')
search_fields = ('title', 'description')
4. ローカル環境での動作確認
開発サーバーの起動
python manage.py runserver
ブラウザで http://127.0.0.1:8000/ にアクセスして動作を確認します。
管理者アカウントの作成
python manage.py createsuperuser
プロンプトに従って、ユーザー名、メールアドレス、パスワードを入力します。
作成後、http://127.0.0.1:8000/admin/ にアクセスして管理サイトにログインできます。
5. Renderへのデプロイ準備
必要なファイルの作成
requirements.txt
プロジェクトの依存関係を記述するファイルを作成します。
asgiref==3.8.1
Django==5.1.7
sqlparse==0.5.3
gunicorn==21.2.0
whitenoise==6.6.0
dj-database-url==2.1.0
python-dotenv==1.0.1
# PostgreSQLは使用しないので削除
# psycopg2-binary==2.9.9
Procfile
Renderがアプリケーションを起動するためのコマンドを記述します。
web: gunicorn todo_project.wsgi
runtime.txt
使用するPythonのバージョンを指定します。
python-3.13.0
.gitignore
バージョン管理から除外するファイルを指定します。
__pycache__/
*.py[cod]
*$py.class
*.so
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
*.sqlite3
.DS_Store
staticfiles/
.env.local
.env.development.local
.env.test.local
.env.production.local
settings.pyの修正
本番環境向けにtodo_project/settings.py
を修正します。
import os
from pathlib import Path
import dj_database_url
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-=h0s7pk9e+#ixlm&aru9#0vg#hv$$!s+fbe6f3da37kb)-^nko')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True # 開発中はTrueに、本番環境ではFalseに設定
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '.onrender.com']
# ... (他の設定)
# 静的ファイルの設定
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# ミドルウェアにWhiteNoiseを追加
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # 追加
# ... (他のミドルウェア)
]
# データベース設定(SQLite)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# セキュリティ設定
if not DEBUG:
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000 # 1年
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
静的ファイルの収集
python manage.py collectstatic
6. Renderへのデプロイ
Renderアカウントの作成
Renderの公式サイトにアクセスし、アカウントを作成します。
新しいWebサービスの作成
- ダッシュボードから「New +」→「Web Service」を選択
- GitHubのリポジトリを接続(事前にGitHubにコードをプッシュしておく必要があります)
- 以下の設定を行います:
-
Name:
todo-project
(任意の名前) -
Environment:
Python
- Region: お近くのリージョンを選択
-
Branch:
main
(または使用するブランチ) - Build Command:
pip install -r requirements.txt && python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic --noinput
- Start Command:
gunicorn todo_project.wsgi
- Plan: 無料プラン(Free)を選択
環境変数の設定
「Environment」タブで以下の環境変数を設定します:
-
SECRET_KEY: 安全な秘密鍵(以下のコマンドで生成できます)
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
デプロイの開始
「Create Web Service」ボタンをクリックしてデプロイを開始します。
ビルドとデプロイのプロセスが完了するまで待ちます(数分かかる場合があります)。
デプロイが完了すると、https://todo-project-xxxx.onrender.com
のようなURLが生成されます。
このURLにアクセスして、アプリケーションが正常に動作することを確認します。
7. トラブルシューティング
デバッグモードの有効化
エラーが発生した場合、一時的にDEBUGモードを有効にしてエラーメッセージを確認できます:
# settings.py
DEBUG = True
データベースの問題
よくある問題として「no such table」エラーがあります。これはマイグレーションが正しく適用されていない場合に発生します。
ビルドコマンドにpython manage.py makemigrations
とpython manage.py migrate
が含まれていることを確認してください。
静的ファイルの問題
静的ファイルが正しく表示されない場合は、以下を確認してください:
-
STATIC_ROOT
が正しく設定されているか -
STATICFILES_STORAGE
にwhitenoise.storage.CompressedManifestStaticFilesStorage
が設定されているか -
collectstatic
コマンドがビルド時に実行されているか
8. データベースについての補足
Renderでの永続的なデータベース
Renderでは、デフォルトではファイルシステムがデプロイごとにリセットされるため、SQLiteデータベースのデータは失われます。永続的なデータを保存するには、以下のいずれかの方法を選択します:
-
PostgreSQLやMySQLの使用(推奨)
外部のミドルウェアを利用します。RenderではPostgreSQLも提供されているため、そちらを利用するのがベターです。
詳しい設定方法は後述します。 -
ディスクの追加
Renderのダッシュボードで永続的なディスクを追加し、そこにSQLiteデータベースを保存する方法もあります。
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join('/opt/render/project/database', 'db.sqlite3'), } }
-
デプロイごとにマイグレーションを実行
小規模なプロジェクトやデモでは、デプロイごとに新しいデータベースを作成する方法も使えます。
この方法ではデータは永続的ではありませんが、設定がシンプルです。
MySQLを使用する場合の設定
もしRenderでMySQLを使用したい場合は、外部のMySQLサービス(例:Amazon RDS、PlanetScaleなど)と接続する必要があります。以下に設定例を示します:
-
必要なパッケージのインストール
pip install mysqlclient
そして
requirements.txt
に追加します:mysqlclient==2.2.2
-
settings.pyの設定
# 環境変数または.envファイルから接続情報を取得 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': os.environ.get('DB_NAME', 'todo_db'), 'USER': os.environ.get('DB_USER', 'root'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': os.environ.get('DB_HOST', 'localhost'), 'PORT': os.environ.get('DB_PORT', '3306'), 'OPTIONS': { 'charset': 'utf8mb4', 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, } }
-
環境変数の設定
Renderのダッシュボードで以下の環境変数を設定します:
-
DB_NAME
: データベース名 -
DB_USER
: ユーザー名 -
DB_PASSWORD
: パスワード -
DB_HOST
: MySQLサーバーのホスト名 -
DB_PORT
: ポート番号(通常は3306)
-
PostgreSQLを使用する場合の最適設定
RenderのマネージドPostgreSQLサービスを使用する場合の最適な設定です:
-
データベースの作成
Renderダッシュボードから「New +」→「PostgreSQL」を選択し、新しいデータベースを作成します。
作成後、接続情報(特にDATABASE_URL
)が提供されます。 -
Webサービスとデータベースの接続
作成したWebサービスの「Environment」タブで、「Add Internal Database」をクリックし、先ほど作成したPostgreSQLデータベースを選択します。
これにより、自動的にDATABASE_URL
環境変数が設定されます。 -
settings.pyの設定
import dj_database_url # DATABASE_URLが設定されていればそれを使用 if 'DATABASE_URL' in os.environ: DATABASES = { 'default': dj_database_url.config( conn_max_age=600, conn_health_checks=True, ) } else: # ローカル開発用のSQLite設定 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }
-
必要なパッケージの追加
psycopg2-binary==2.9.9
この設定により、ローカル開発ではSQLiteを使用し、Render上ではPostgreSQLを使用するハイブリッド構成が実現できます。
9. その他の参考情報
RenderでのPython環境とDocker環境の違い
Renderでは、Pythonアプリケーションをデプロイする方法として「Python」環境と「Docker」環境の2つのオプションがあります。それぞれの特徴を比較してみましょう。
Python環境(Native Environment)
メリット:
- 設定が簡単で、Python特有の知識だけで十分
- Renderによって最適化されたPython実行環境
-
requirements.txt
ファイルのみでパッケージ管理が可能 - ビルドが高速(通常、Dockerビルドより速い)
- Renderによる自動的な環境のアップグレードと保守
デメリット:
- カスタマイズの自由度がやや低い
- Pythonアプリケーション専用(他の言語との混在が難しい)
- システムレベルの依存関係のインストールが限定的
設定例:
# Build Command
pip install -r requirements.txt && python manage.py migrate && python manage.py collectstatic --noinput
# Start Command
gunicorn todo_project.wsgi
Docker環境
メリット:
- 完全なカスタマイズが可能(どんなコンテナイメージも使用可能)
- 複雑な依存関係や特殊なシステムパッケージのインストールが可能
- 開発と本番環境の完全な一貫性を確保できる
- 複数の言語や技術を組み合わせたアプリケーションに適している
- 特定のPythonバージョンや特殊なライブラリの使用が容易
デメリット:
- Dockerfileの作成と管理が必要(学習コストが高い)
- ビルド時間が長くなる場合がある
- イメージサイズの管理が必要
- 設定ミスによるデバッグが複雑になることがある
Dockerfile例:
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "todo_project.wsgi:application", "--bind", "0.0.0.0:8000"]
どちらを選ぶべきか?
-
Python環境が適している場合:
- 標準的なDjangoアプリケーション
- Docker知識がない、または学習中の場合
- シンプルな依存関係を持つプロジェクト
- 迅速なデプロイを優先する場合
-
Docker環境が適している場合:
- カスタムシステムパッケージが必要な場合
- 特殊なPython拡張や特定バージョンのPythonが必要な場合
- マイクロサービスアーキテクチャを採用している場合
- 複数の言語やサービスを組み合わせている場合
- チーム内にDocker経験者がいる場合
今回のTODOアプリケーションのような比較的シンプルなDjangoアプリケーションでは、Python環境を選択するのが最も簡単で効率的です。より複雑なプロジェクトや特殊な要件がある場合は、Docker環境を検討することをおすすめします。
まとめ
この記事では、DjangoでTODOアプリケーションを作成し、Renderにデプロイする方法を解説しました。
基本的なCRUD操作を持つアプリケーションを構築し、本番環境にデプロイするまでの手順を学びました。
さらに、異なるデータベース(SQLite, PostgreSQL, MySQL)の設定方法や、RenderでのPython環境とDocker環境の違いについても解説しました。
Djangoは強力なWebフレームワークであり、さまざまなWebアプリケーションの開発に利用できます。
Renderは、簡単にPythonアプリケーションをデプロイできるプラットフォームで、個人プロジェクトや小規模なアプリケーションの公開に適しています。
ぜひこの記事を参考に、自分だけのWebアプリケーションを開発してみてください!