Djangoで1行掲示板にユーザーが投稿するための新規投稿機能を作ってみましょう。新規投稿機能を作成するには投稿フォームとそれを表示するWebページ、投稿内容をデータベースに保存するなど複数の機能が必要になります。
目次
- 必要な機能のリストアップ
- ルーティング
- 新規投稿ページへ遷移するためのボタンをindex.htmlに配置
- 新規投稿フォームを定義
- 新規投稿ページを呼び出すための関数を作成
- 投稿用Webページ(new.html)の作成
- 投稿内容をデータベースに保存する関数を作成
- 投稿完了ページ(posted.html)を作成
- 動作確認
必要な機能のリストアップ
まずはじめに必要になる機能とページを確認しておきましょう。
掲示板の新規投稿には次の各機能が必要となります。
- 投稿用Webページ、投稿保存機能へのルーティング(urls.pyに記述)
- 新規投稿ページへ遷移するためのボタン(index.htmlに配置)
- 新規投稿用のWebページ(new.htmlを作成)
- 投稿内容をデータベースに保存する関数(views.pyに記述)
- 投稿完了ページ(posted.html)を作成
これらを1つずつ作っていきましょう。
ルーティング
まずはユーザーが各URLにアクセスした場合のルーティング処理を作成します。
/bbs/urls.py に次のように記述します。
from django.urls import path from . import views app_name = 'bbs' urlpatterns = [ path('', views.index, name='index'), path('<int:id>', views.detail, name='detail'), path('new', views.new, name='new'), # 投稿用WebページのURL path('create', views.create, name='create'), # 新規投稿をデータベースに保存するためのURL ]
ユーザーが /bbs/new/ にアクセスすると views.py の new関数を、/bbs/create/ にアクセスすると views.py の create関数を呼び出します。
また、それぞれname属性を付けておいたので、newやnameといった名前でこのURLをリンクで呼び出せます。
新規投稿ページへ遷移するためのボタンをindex.htmlに配置
投稿一覧ページに新規投稿ページへの遷移ボタンを配置しておきましょう。
{% extends "./base.html" %} {% block content %} <h1>Djangoで作る1行掲示板</h1> {% if searchForm %} <form action='{% url "bbs:index" %}' method="get"> <div> {{ searchForm }} <input type="submit" value="検索"> <a href='{% url "bbs:index" %}'>クリア</a> </div> </form> {% endif %} {% for article in articles %} <p> <a href='{% url "bbs:detail" article.id %}'>{{ article.content }}</a> {{ article.user_name }} </p> {% endfor %} <!-- 新規投稿ページへの遷移ボタン --> <p> <button onclick='location.href="{% url "bbs:new" %}"'>新規投稿</button> </p> {% endblock %}
先ほど urls.py で /new/ のURLを new という名前で呼び出せるようにしておいたので、25行目のリンクで /bbs/new/ へ遷移することができます。
新規投稿フォームを定義
次に新規投稿フォームを定義しましょう。
forms.py に次のように記述します。
from django import forms from .models import Article # models.pyからArticleクラスをインポート # SearchFormクラスを定義 class SearchForm(forms.Form): keyword = forms.CharField(label='', max_length=50) # 新規投稿フォームを定義 class ArticleForm(forms.ModelForm): class Meta: model = Article fields = ('content', 'user_name')
データベースに書き込むためのフォームなので、データ形式を指定する時にモデルを参照するだけで記述できます。
新規投稿ページを呼び出すための関数を作成
作成したフォームを利用して新規投稿用のWebページを呼び出すための関数を作成します。
views.py に次のように記述します。
from django.shortcuts import render,get_object_or_404 from django.http import HttpResponse from .models import Article from .forms import SearchForm from .forms import ArticleForm # forms.pyからArticleFormクラスをインポート def index(request): searchForm = SearchForm(request.GET) if searchForm.is_valid(): keyword = searchForm.cleaned_data['keyword'] articles = Article.objects.filter(content__contains=keyword) else: searchForm = SearchForm() articles = Article.objects.all() context = { 'articles': articles, 'searchForm': searchForm, } return render(request, 'bbs/index.html', context) def detail(request, id): article = get_object_or_404(Article, pk=id) context = { 'article': article, } return render(request, 'bbs/detail.html', context) # 新規投稿画面のWebページを返すnew関数 def new(request): articleForm = ArticleForm() # ArticleFormオブジェクトを生成 # テンプレート側でarticleFormのデータを取り出せるようにcontextに渡す context = { 'articleForm': articleForm, } return render(request, 'bbs/new.html', context) # new.htmlというテンプレートを返す
新規投稿フォームを呼び出すだけなので
- forms.pyからArticleFormクラスをインポート
- articleFormオブジェクトを用意してcontextに追加
- テンプレート(new.html)を呼び出す
これだけです。
投稿用Webページ(new.html)の作成
views.py で呼び出すように記述した new.html というテンプレートファイルを作成します。
/templates/bbs/ に new.html という名前でファイルを作成し、次のように記述します。
{% extends "./base.html" %} {% block content %} <h1>Djangoで作る新規投稿フォーム</h1> <form action='{% url "bbs:create" %}' method="post"> {% csrf_token %}<!-- セキュリティのための記述 --> {{ articleForm }}<!-- views.pyから受け取ったarticleFormを表示 --> <button type='submit'>投稿</button> <a href='{% url "bbs:index" %}'>一覧ページへ戻る</a> </form> {% endblock %}
forms.py で定義した ArticleForm クラスを元に、views.py の new関数の中でオブジェクトを作成してテンプレートに渡しているので、テンプレート側では articleForm という変数名を指定するだけで、必要な項目(今回はcontentとUser name)が用意されたフォームを作成してくれます。
また、6行目では「投稿」ボタンをクリックすると create という名前のルートをPOSTメソッドで呼び出すよう記述しています。
※csrf_tokenはDjangoが用意してくれているセキュリティ機能です。フォームがデータを送信する時にトークン情報を一緒に送信し、リクエストを受け取ったViewが、トークンが正しいものがどうか検証し、正常なリクエストだと認められれば処理を実行してくれます。
投稿内容をデータベースに保存する関数を作成
次に、投稿用Webページで「投稿」ボタンを押した時に呼び出される create関数を作成しましょう。
views.py に次のように記述します。
from django.shortcuts import render,get_object_or_404 from django.http import HttpResponse from .models import Article from .forms import SearchForm from .forms import ArticleForm # forms.pyからArticleFormクラスをインポート def index(request): searchForm = SearchForm(request.GET) if searchForm.is_valid(): keyword = searchForm.cleaned_data['keyword'] articles = Article.objects.filter(content__contains=keyword) else: searchForm = SearchForm() articles = Article.objects.all() context = { 'articles': articles, 'searchForm': searchForm, } return render(request, 'bbs/index.html', context) def detail(request, id): article = get_object_or_404(Article, pk=id) context = { 'article': article, } return render(request, 'bbs/detail.html', context) # 新規投稿画面のWebページを返すnew関数 def new(request): articleForm = ArticleForm() context = { 'articleForm': articleForm, } return render(request, 'bbs/new.html', context) #新規投稿データを保存するcreate関数 def create(request): # リクエストのメソッドがPOSTなら if request.method == 'POST': articleForm = ArticleForm(request.POST) # リクエストから取り出したデータを代入 # 受け取ったデータが正常なら if articleForm.is_valid(): article = articleForm.save() # データを保存 context = { 'article': article, } return render(request, 'bbs/posted.html', context) # detail.htmlを返す
この関数は新規投稿フォームからデータを受け取った時、POSTメソッドかどうか、受け取ったデータが正常かどうかをチェックし、問題なければデータを保存します。
その後、保存したデータを context に追加して、テンプレートファイル(posted.html)を呼び出します。
投稿完了ページ(posted.html)を作成
最後に、ユーザーに投稿完了を知らせる投稿完了ページのテンプレートを作成しましょう。
/templates/bbs/ に posted.html という名前でファイルを作成し、次のように記述します。
{% extends "./base.html" %} {% block content %} <h1>{{ article.id }}の投稿が完了しました!</h1> <p>{{ article.content }}, {{article.user_name }}</p> <p><a href='{% url "bbs:index" %}'>一覧ページへ戻る</a></p> {% endblock %}
投稿した記事のidと投稿内容、投稿者名、そして一覧ページに戻るためのリンクを配置しています。
動作確認
それでは動作確認です。
Djangoコマンドを使ってサーバーを起動し、ブラウザで確認してみましょう。
http://127.0.0.1:8000/bbs にアクセスします。
新規投稿ボタンをクリックしてみましょう。
このように新規投稿フォームが表示されます。
※一切ページデザインをしていないのでガタガタですが、見た目は後からいくらでも整えることができます。
試しにデータを入力して「投稿」してみましょう。
「投稿」ボタンをクリック
投稿完了ページへと遷移しました。
※何度かテストしたのでidがずれてしまっています。気にしないで下さい。
「一覧ページへ戻る」をクリックしてみましょう。
先ほど投稿した内容が一覧ページにも反映されています。
新規投稿機能の完成です!