😊

DjangoとTailwindCSSを組み合わせた認証機能付きWebアプリの実装

に公開

DjangoとTailwindCSSを組み合わせた認証機能付きWebアプリの実装

はじめに

Webアプリケーション開発において、ユーザー認証機能は欠かせない要素の一つです。本記事では、Django 5.2とTailwindCSSを組み合わせて、メール認証機能付きのモダンなWebアプリケーションを構築する方法を解説します。

この記事で学べること

  • Django 5.2の最新機能を活用した認証システムの構築
  • TailwindCSSを使ったモダンなUIの実装
  • メール認証によるセキュアなユーザー登録フロー
  • カスタムユーザーモデルの実装

使用技術

  • バックエンド: Django 5.2.7
  • フロントエンド: TailwindCSS 3.4.17
  • パッケージ管理: uv(Python)、npm(Node.js)
  • メール送信: django-anymail(開発環境ではコンソール出力)
  • データベース: SQLite

技術スタックの選定理由

Django 5.2を選ぶ理由

Django 5.2は、LTS(Long Term Support)バージョンです。以下の特徴があります:

  • パフォーマンスの向上: 非同期処理のサポートが強化
  • セキュリティの強化: 最新のセキュリティパッチが適用

TailwindCSSを選ぶ理由

TailwindCSSは、ユーティリティファーストのCSSフレームワークです:

  • 開発速度の向上: クラスベースのスタイリングで高速開発
  • 一貫性のあるデザイン: デザインシステムの統一

メール認証の重要性

メール認証を実装することで:

  • セキュリティの向上: 有効なメールアドレスの確認
  • スパム対策: 不正な登録の防止
  • ユーザー体験の向上: 確実なアカウント有効化

プロジェクト構成

ディレクトリ構造

django-tailwindcss-auth/
├── app/                    # メインアプリケーション
│   ├── models.py          # カスタムユーザーモデル
│   ├── views.py           # ビュー(認証ロジック)
│   ├── forms.py           # フォーム(バリデーション)
│   └── urls.py            # URL設定
├── config/                # Django設定
│   ├── settings.py        # 設定ファイル
│   └── urls.py            # メインURL設定
├── templates/             # HTMLテンプレート
│   ├── auth/              # 認証関連テンプレート
│   ├── base.html          # ベーステンプレート
│   └── index.html         # トップページ
├── static/                # 静的ファイル
│   └── css/
│       ├── input.css      # TailwindCSS入力ファイル
│       └── output.css     # ビルドされたCSS
├── pyproject.toml         # Python依存関係
├── package.json           # Node.js依存関係
└── tailwind.config.js     # TailwindCSS設定

依存関係の管理

Python依存関係(pyproject.toml)

[project]
name = "django-tailwindcss-auth"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "django>=5.2.7",
    "django-anymail>=13.1",
    "python-dotenv>=1.1.1",
]

Node.js依存関係(package.json)

{
  "devDependencies": {
    "tailwindcss": "^3.4.17"
  },
  "scripts": {
    "build:watch": "tailwindcss -i ./static/css/input.css -o ./static/css/output.css --watch"
  }
}

実装のポイント

1. カスタムユーザーモデル

DjangoのデフォルトのUserモデルを拡張して、メールアドレスを必須フィールドにします:

# app/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """カスタムユーザーモデル"""
    
    email = models.EmailField(unique=True, verbose_name="メールアドレス")
    
    def __str__(self):
        return self.username

ポイント:

  • AbstractUserを継承してDjangoの認証機能を活用
  • emailフィールドをunique=Trueで一意性を保証
  • 日本語のverbose_nameで管理画面での表示を改善

2. フォームの実装

ユーザー登録フォームでは、TailwindCSSのクラスを直接指定してモダンなUIを実現:

# app/forms.py
class SignUpForm(UserCreationForm):
    """サインアップフォーム"""
    
    email = forms.EmailField(
        label="メールアドレス",
        required=True,
        widget=forms.EmailInput(
            attrs={
                "class": "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",
                "placeholder": "メールアドレスを入力",
            }
        ),
    )
    # ... 他のフィールドも同様に実装

ポイント:

  • UserCreationFormを継承してDjangoの認証機能を活用
  • widgetattrsでTailwindCSSクラスを指定
  • バリデーション機能も継承して利用

3. TailwindCSSの統合

設定ファイル(tailwind.config.js)

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./templates/**/*.html",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

入力ファイル(static/css/input.css)

@tailwind base;
@tailwind components;
@tailwind utilities;

ビルドコマンド

npm run build:watch

4. メール認証の実装

ユーザー登録時にメール認証を送信する機能:

# app/forms.py
def _send_activation_email(self, user):
    subject = "[Django TailwindCSS Auth] 仮登録完了のお知らせ"
    message_template = """
Django TailwindCSS Auth にご登録いただきありがとうございます。
以下のURLをクリックして、本登録を完了してください。
"""
    uid = urlsafe_base64_encode(force_bytes(user.pk))
    token = default_token_generator.make_token(user)
    activate_url = settings.FRONTEND_URL + f"/activate/{uid}/{token}/"
    message = message_template + activate_url
    user.email_user(subject, message)

ポイント:

  • Djangoのdefault_token_generatorを使用してセキュアなトークン生成
  • urlsafe_base64_encodeでURLセーフなエンコード
  • user.email_user()でメール送信

コード解説

1. ビューの実装

認証機能の核となるビュークラスを実装します:

# app/views.py
class SignUpView(CreateView):
    """サインアップビュー"""
    
    form_class = SignUpForm
    template_name = "auth/signup.html"
    success_url = reverse_lazy("app:signup_done")
    
    def form_valid(self, form):
        user = form.save()  # メール送信も含む
        # ログインはしない(アクティベーションが必要)
        return redirect(self.success_url)

実装のポイント:

  • CreateViewを継承してCRUD操作を簡素化
  • form_validメソッドでフォーム処理後の動作をカスタマイズ
  • アクティベーション前はログインさせない設計

2. テンプレートの実装

TailwindCSSを使ったモダンなUIテンプレート:

<!-- templates/auth/signup.html -->
{% extends 'base.html' %}

{% block content %}
<div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
    <div class="max-w-md w-full space-y-8">
        <div>
            <div class="mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-blue-100">
                <svg class="h-6 w-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
                </svg>
            </div>
            <h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
                新規登録
            </h2>
        </div>
        
        <form class="mt-8 space-y-6" method="post">
            {% csrf_token %}
            <!-- フォームフィールド -->
        </form>
    </div>
</div>
{% endblock %}

デザインのポイント:

  • min-h-screenでフルスクリーン表示
  • flex items-center justify-centerで中央配置
  • space-y-8で要素間のスペーシングを統一
  • レスポンシブデザイン(sm:px-6 lg:px-8

3. エラーハンドリング

フォームバリデーションエラーの表示:

{% if form.non_field_errors %}
    <div class="bg-red-50 border border-red-200 rounded-md p-4">
        <div class="flex">
            <div class="flex-shrink-0">
                <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
                </svg>
            </div>
            <div class="ml-3">
                <h3 class="text-sm font-medium text-red-800">
                    エラーが発生しました
                </h3>
                <div class="mt-2 text-sm text-red-700">
                    {% for error in form.non_field_errors %}
                        <p>{{ error }}</p>
                    {% endfor %}
                </div>
            </div>
        </div>
    </div>
{% endif %}

4. アクティベーション機能

メール認証によるアカウント有効化:

# app/views.py
def activate_user(uidb64, token):
    """ユーザーアクティベーション関数"""
    try:
        uid = urlsafe_base64_decode(uidb64).decode()
        user = User.objects.get(pk=uid)
    except Exception:
        return False
    
    if default_token_generator.check_token(user, token):
        user.is_active = True
        user.save()
        return True
    return False

class ActivateView(TemplateView):
    """アクティベーションビュー"""
    
    template_name = "auth/activate.html"
    
    def get(self, request, uidb64, token, *args, **kwargs):
        result = activate_user(uidb64, token)
        context = self.get_context_data(result=result)
        return self.render_to_response(context)

セキュリティのポイント:

  • urlsafe_base64_decodeで安全にデコード
  • default_token_generator.check_tokenでトークンの有効性を検証
  • 例外処理で不正なアクセスを防止

5. 設定ファイルの最適化

Django設定(config/settings.py)

# カスタムユーザーモデルの設定
AUTH_USER_MODEL = 'app.User'

# メール設定
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'  # 開発環境
# EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend'  # 本番環境

# 静的ファイルの設定
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']

環境変数の管理(.env)

# 基本設定
SECRET_KEY=your-secret-key-here
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1

# データベース設定
DATABASE_URL=sqlite:///db.sqlite3

# メール設定(オプション)
USE_MAILGUN=False
MAILGUN_API_KEY=your_mailgun_api_key_here
MAILGUN_SENDER_DOMAIN=your_domain.mailgun.org

# フロントエンドURL
FRONTEND_URL=http://localhost:8000

開発環境での動作確認

サーバーの起動

Djangoサーバーの起動

uv run python manage.py runserver

TailwindCSSの監視(別ターミナル)

npm run build:watch

これで http://127.0.0.1:8000 でアプリケーションにアクセスできます。

セキュリティの考慮事項

  1. CSRFトークン: フォームにCSRFトークンを適切に設定
  2. メール認証: 有効なメールアドレスの確認
  3. バリデーション: フォーム入力の適切な検証

まとめ

本記事では、Django 5.2とTailwindCSSを組み合わせた認証システムの実装方法を解説しました。

実装した機能

  • ✅ カスタムユーザーモデル(メールアドレス必須)
  • ✅ ユーザー登録・ログイン機能
  • ✅ メール認証によるアカウント有効化
  • ✅ TailwindCSSによるモダンなUI

技術的な学び

  1. Django 5.2の活用: 最新のLTSバージョンの機能を最大限活用
  2. TailwindCSSの統合: ユーティリティファーストのCSS設計
  3. セキュリティの実装: メール認証による安全なユーザー登録
  4. モダンな開発環境: uvとnpmを使った効率的な開発

学習リソース


この記事が、DjangoとTailwindCSSを使ったWebアプリケーション開発の参考になれば幸いです。質問やフィードバックがあれば、お気軽にお聞かせください。

おわりに

このプロジェクトをベースに、さらなる機能拡張やカスタマイズに取り組んでみてください。Webアプリケーション開発の楽しさを感じていただければと思います。

Discussion