djangoで単純な掲示板(ログイン、編集、削除)を作ってみた。
新しい Django プロジェクトを作る
1 2 3 4 5 |
django-admin startproject mybbs cd mybbs # アプリ(掲示板機能)を作る python manage.py startapp board |
settings.py を開いて、INSTALLED_APPS に追加(忘れがち)
1 2 3 4 |
INSTALLED_APPS = [ ... 'board', ] |
掲示板の書き込み(投稿)モデルを作る
board/models.py にモデルを追加
1 2 3 4 5 6 7 8 9 10 11 |
from django.db import models from django.contrib.auth.models import User class Post(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE) # 投稿者 title = models.CharField(max_length=200) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title |
データベースを作成。初期標準テーブル+Postテーブルが生成
1 2 |
python manage.py makemigrations python manage.py migrate |
投稿フォームを作る
board/forms.py を作成(無ければ作る)
1 2 3 4 5 6 7 |
from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'content'] |
ビューを作る
board/views.py に以下を追加していきます。
laravelのcontrollerと同じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# board/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth import login from .models import Post from .forms import PostForm, SignUpForm # =========================== # 投稿一覧を表示するビュー # =========================== def post_list(request): # 投稿を新しい順に取得 posts = Post.objects.all().order_by('-created_at') return render(request, 'board/post_list.html', {'posts': posts}) # =========================== # 投稿詳細を表示するビュー # =========================== def post_detail(request, pk): # 指定された投稿を取得(存在しなければ 404) post = get_object_or_404(Post, pk=pk) return render(request, 'board/post_detail.html', {'post': post}) # =========================== # 新規投稿を作成するビュー # ログイン必須 # =========================== @login_required def post_create(request): if request.method == 'POST': # フォームにデータをバインド form = PostForm(request.POST) if form.is_valid(): # データベースには保存せず、一旦取り出す post = form.save(commit=False) post.author = request.user # 投稿者をログインユーザーに設定 post.save() # 保存 return redirect('post_detail', pk=post.pk) else: # 新規投稿用の空フォームを表示 form = PostForm() return render(request, 'board/post_form.html', {'form': form}) # =========================== # 投稿を編集するビュー # ログイン必須 # 投稿者本人以外は編集不可 # =========================== @login_required def post_edit(request, pk): post = get_object_or_404(Post, pk=pk) # 投稿者本人以外は編集できない if post.author != request.user: return redirect('post_detail', pk=pk) if request.method == 'POST': form = PostForm(request.POST, instance=post) if form.is_valid(): form.save() return redirect('post_detail', pk=pk) else: # 編集用に既存の投稿をフォームに渡す form = PostForm(instance=post) return render(request, 'board/post_form.html', {'form': form}) # =========================== # 投稿を削除するビュー # ログイン必須 # 投稿者本人以外は削除不可 # =========================== @login_required def post_delete(request, pk): post = get_object_or_404(Post, pk=pk) # 投稿者本人以外は削除できない if post.author != request.user: return redirect('post_detail', pk=pk) if request.method == 'POST': post.delete() return redirect('post_list') return render(request, 'board/post_confirm_delete.html', {'post': post}) # =========================== # ユーザー新規登録ビュー(サインアップ) # 認証後、自動ログインしてトップへ # =========================== def signup(request): if request.method == 'POST': form = SignUpForm(request.POST) if form.is_valid(): user = form.save() # 新規作成したユーザーで自動ログイン login(request, user) return redirect('post_list') else: form = SignUpForm() return render(request, 'registration/signup.html', {'form': form}) |
掲示板アプリのURLを設定(ルーティング)
board/urls.py を新規作成
1 2 3 4 5 6 7 8 9 10 |
from django.urls import path from . import views # board/views.pyの関数を割り当てているのでimport urlpatterns = [ path('', views.post_list, name='post_list'), path('post/<int:pk>/', views.post_detail, name='post_detail'), path('post/new/', views.post_create, name='post_create'), path('post/<int:pk>/edit/', views.post_edit, name='post_edit'), path('post/<int:pk>/delete/', views.post_delete, name='post_delete'), ] |
プロジェクトの urls.py にも include する(掲示板アプリのboard/urls.pyの上位的存在)
1 2 3 4 5 6 7 8 9 10 |
from django.contrib import admin from django.urls import path, include from board import views urlpatterns = [ path('', include('board.urls')), # 掲示板アプリにそのまま渡す path('accounts/signup/', views.signup, name='signup'), # ユーザ登録用(マッチング的にaccounts/より上に記述) path('accounts/', include('django.contrib.auth.urls')), # ログイン用 path('admin/', admin.site.urls), ] |
ブラウザに表示されるHTMLテンプレートを作る
board/templates/board/ を作って以下の HTML を配置。
投稿一覧 post_list.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{% if user.is_authenticated %} <form action="{% url 'logout' %}" method="post"> {% csrf_token %} <button type="submit">ログアウト</button> </form> {% else %} <a href="{% url 'login' %}">ログイン</a> | <a href="{% url 'signup' %}">新規登録</a> {% endif %} <h1>掲示板</h1> {% if user.is_authenticated %} <a href="{% url 'post_create' %}">新規投稿</a> {% else %} <a href="{% url 'login' %}">ログインして投稿</a> {% endif %} <ul> {% for post in posts %} <li> <a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a> - {{ post.author }} </li> {% endfor %} </ul> |
post_detail.html
投稿の詳細ページ(自分の投稿なら、編集・削除へのリンク)
1 2 3 4 5 6 7 8 9 |
<h1>{{ post.title }}</h1> <p>{{ post.content }}</p> <p>投稿者: {{ post.author }}</p> {% if user == post.author %} <a href="{% url 'post_edit' post.pk %}">編集</a> <a href="{% url 'post_delete' post.pk %}">削除</a> {% endif %} <a href="{% url 'post_list' %}">一覧に戻る</a> |
新規投稿のWebフォーム post_form.html
1 2 3 4 5 6 7 |
<h1>投稿フォーム</h1> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">送信</button> </form> <a href="{% url 'post_list' %}">キャンセル</a> |
投稿の削除確認ページ post_confirm_delete.html
1 2 3 4 5 6 |
<h1>本当に削除しますか?</h1> <form method="post"> {% csrf_token %} <button type="submit">削除</button> </form> <a href="{% url 'post_detail' post.pk %}">キャンセル</a> |
ログイン・ユーザー新規登録のHTMLテンプレートを作成
mybbs/board/templates/registration/signup.html
mybbs/board/templates/registration/login.html
を追加
1 2 3 4 5 6 7 8 |
<!-- templates/registration/signup.html --> <h1>新規ユーザー登録</h1> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">登録</button> </form> <a href="{% url 'login' %}">ログイン画面へ</a> |
1 2 3 4 5 6 7 |
<!-- templates/registration/login.html --> <h1>ログイン</h1> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">ログイン</button> </form> |
board/forms.py にユーザ新規登録のWebフォーム処理を追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# board/forms.py from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from .models import Post # =========================== # 投稿フォーム # =========================== class PostForm(forms.ModelForm): """ 投稿作成・編集用のフォーム Post モデルの title と content を入力させる """ class Meta: model = Post fields = ['title', 'content'] # =========================== # ユーザー新規登録フォーム # =========================== class SignUpForm(UserCreationForm): """ 新規ユーザー登録用フォーム Django 標準の UserCreationForm を拡張し、 username, email, password1, password2 を扱う """ class Meta: model = User fields = ('username', 'email', 'password1', 'password2') |
python manage.py runserver で確認する
ちなみに404エラー&500エラーのページも作れる。
settings.pyでデバッグモード終了
1 2 3 |
DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', 'localhost'] |
それぞれテンプレートファイルを作成するだけ
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!-- templates/404.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ページが見つかりません</title> </head> <body> <h1>お探しのページは見つかりませんでした</h1> <p>URLが間違っているか、すでに削除された可能性があります。</p> <a href="/">トップに戻る</a> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!-- templates/500.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>サーバーエラー</title> </head> <body> <h1>内部サーバーエラーが発生しました</h1> <p>しばらくしてから再度お試しください。</p> <a href="/">トップに戻る</a> </body> </html> |