テンプレートの共通化
共通部分をまとめると、Webデザインの作成やメンテナンスを効率よく進めることができます。
base.htmlを作成
<!-- myapp/bbs/templates/bbs/base.html -->
< !DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<title>paiza bbs</title>
<style>body {padding: 80px;}</style>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
index.htmlの共通部分を分離
<!-- myapp/bbs/templates/bbs/index.html -->
{% extends './base.html' %} <!-- 共通テンプレートを指定 -->
{% block content %}
<h1>paiza bbs</h1>
<p>{{ message }}</p>
{% for article in articles %}
<p>
{{ article.content }},{{ article.user_name }},
<a href='{% url "bbs:detail" article.id %}'>詳細</a>,
<a href='{% url "bbs:delete" article.id %}'>削除</a>
</p>
{% endfor %}
<p>
<a href='{% url "bbs:create" %}'>新規</a>
</p>
{% endblock %}
detail.htmlの共通部分を分離
<!-- myapp/bbs/templates/bbs/detail.html -->
{% extends './base.html' %} <!-- 共通テンプレートを指定 -->
{% block content %}
<h1>paiza bbs</h1>
<p>{{ message }}</p>
<p>{{ article.content }}, {{ article.user_name }}</p>
<p><a href='{% url "bbs:index" %}'>一覧</a></p>
{% endblock %}
掲示板にBootstrapを適用
CSSフレームワークのBootstrapを利用すると、Webアプリケーションのデザインを簡単に設定できます。
Bootstrapを適用する
<!-- myapp/bbs/templates/bbs/base.html -->
< !DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<!-- metaタグでviewportを指定 -->
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'/>
<title>paiza bbs</title>
<!-- bootstrapを読み込み -->
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css'/>
<style>body {padding-top: 80px;}</style>
</head>
<body>
<!-- ナビゲーションバーを追加 -->
<nav class='navbar navbar-expand-md navbar-dark bg-dark fixed-top'>
<a class='navbar-brand' href='{% url "bbs:index" %}'>paiza bbs</a>
</nav>
<div class='container'> <!-- bootstrapがデザインしてくれる -->
{% block content %}
{% endblock %}
</div>
</body>
</html>
※ bootstrap4をダウンロードして使用する場合は以下を参照
Bootstrap4の導入方法と基本を徹底解説!
Django staticファイル まとめ – Qiita
Bootstrapでページの見栄えを整える
Bootstrapには、テーブルタグやボタンに見栄えの良いスタイルが用意してあるので、これを利用していきます。
一覧ページをテーブルとボタンに変更
<!-- myapp/bbs/templates/bbs/index.html -->
{% extends './base.html' %}
{% block content %}
<h1>paiza bbs</h1>
<p>{{ message }}</p>
<!-- stripedで1行毎に色を付ける -->
<table class='table table-striped table-hover'>
{% for article in articles %}
<tr>
<td>{{ article.content }}</td>
<td>{{ article.user_name }}</td>
<td>
<!-- リンクをボタンに変更 -->
<a href='{% url "bbs:detail" article.id %}' class='btn btn-outline-primary'>詳細</a>
<a href='{% url "bbs:delete" article.id %}' class='btn btn-outline-secondary'>削除</a>
</td>
</tr>
{% endfor %}
</table>
<div>
<a href='{% url "bbs:create" %}' class='btn btn-outline-primary'>新規</a>
</div>
{% endblock %}
詳細ページのボタンを変更
<!-- myapp/bbs/templates/bbs/detail.html -->
{% extends './base.html' %}
{% block content %}
<h1>paiza bbs</h1>
<p>{{ message }}</p>
<p>{{ article.content }}, {{ article.user_name }}</p>
<p>
<a href='{% url "bbs:index" %}' class='btn btn-outline-primary'>一覧</a>
</p>
{% endblock %}
検索フォームを設置する
Djangoでフォームを使うための基本的な操作を理解していきます。
フォームを利用する流れ
- forms.py: フォームのクラスで、データ形式を定義する
- views.py: フォームから受け取ったデータを処理して、フォームオブジェクトをテンプレートに渡す
- index.html: フォームを表示する
forms.pyを記述
# myapp/bbs/forms.py
from django import forms
class SearchForm(forms.Form): # SearchFormクラスを定義
# データ形式が文字列のkeyword変数を定義
keyword = forms.CharField(label='検索', max_length=100)
views.pyにフォームオブジェクトを追加
# myapp/bbs/views.py
from .forms import SearchForm
def index(request):
searchForm = SearchForm(request.GET)
# フォームから正常なデータを受信した場合
if searchForm.is_valid():
keyword = searchForm.cleaned_data['keyword'] # keyword変数にその値を代入
# キーワードに該当する投稿をfilterメソッドで取り出す
articles = Article.objects.filter(content__contains=keyword)
else:
searchForm = SearchForm()
articles = Article.objects.all()
context = {
'message': 'Hello Django',
'articles': articles,
'searchForm': searchForm,
}
return render(request, 'bbs/index.html', context)
テンプレートにフォームを追加
<!-- myapp/bbs/templates/bbs/index.html -->
{% extends './base.html' %}
{% block content %}
<h1>paiza bbs</h1>
<p>{{ message }}</p>
{% if searchForm %}
<!-- OKボタンを押すと、getメソッドをindex関数を呼び出す -->
<form action='{% url "bbs:index" %}' method='get'>
<div class='form-group'>
{{ searchForm }} <!-- ビューから受け取ったsearchFormを表示 -->
<input type="submit" class="btn btn-outline-primary" value="OK" />
<a href="{% url 'bbs:index' %}" class="btn btn-outline-secondary">クリア</a>
</div>
</form>
{% endif %}
掲示板のルーティングを設計する
投稿機能を作成する為のルーティングを設計していきます。
掲示板アプリケーションのルーティング設定
| URL | 関数 | 呼び出す機能 |
|---|---|---|
| bbs/ | index() | 投稿一覧 |
| bbs/(id) | detail() | 個別投稿 |
| bbs/new | new() | 新規作成 |
| bbs/create | create() | 新規投稿 |
| bbs/(id)/edit | edit() | 編集 |
| bbs/(id)/update | update() | 更新 |
| bbs/(id)/delete | delete() | 削除 |
urls.pyにルートを追加
# myapp/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'), # 追加
path('create', views.create, name='create'),
path('</int:id><int:id>/edit', views.edit, name='edit'), # 追加
path('</int:id><int:id>/update', views.update, name='update'), # 追加
path('</int:id><int:id>/delete', views.delete, name='delete'),
]
views.pyに関数を追加
# myapp/bbs/views.py
def new(request):
return HttpResponse('this is new.')
def edit(request, id):
return HttpResponse('this is edit ' + str(id))
def update(request, id):
return HttpResponse('this is update ' + str(id))
以下にアクセスして、想定通りの出力があることを確認します。
http://localhost:8000/bbs/new
http://localhost:8000/bbs/1/edit
http://localhost:8000/bbs/1/update
ライブラリのインストール
データベースを更新するフォームでBootstrapを使用できるように、Django Bootstrap4ライブラリをインストールします。
$ pip install django-bootstrap4 $ pip list # 確認
setting.pyを修正
# settings.py
INSTALLED_APPS = [
'bbs.apps.BbsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap4',
]
新規投稿フォームを作成する
forms.pyで投稿フォームのデータ形式を定義して、views.pyでindex関数にコードを記述していきます。
forms.pyに新規投稿フォームを定義
# myapp/bbs/forms.py
from django import forms
from .models import Article
# 投稿用フォームの定義
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('content', 'user_name')
new関数を記述
# myapp/bbs/views.py
from .forms import ArticleForm
def new(request):
# ①ArticleFormオブジェクトを用意
articleForm = ArticleForm()
context = {
'message': 'New Article',
'articleForm': articleForm, # ②コンテキストに追加
}
# ③テンプレートの呼び出し
return render(request, 'bbs/new.html', context)
投稿の保存機能を完成させる
前回作成した、新規投稿を格納するcreate関数と投稿フォームを組み合わせていきます。
new.htmlの作成
<!-- myapp/bbs/templates/bbs/new.html -->
{% extends './base.html' %}
{% load bootstrap4 %}
{% block content %}
<h1>{{ message }}</h1>
<!-- 作成するボタンをクリックすると、createルートをpostメソッドで呼び出す -->
<form action='{% url "bbs:create" %}' method='post' class='form'>
{% csrf_token %} <!-- セキュリティの為の記述 -->
<!-- bootstrapを利用して、articleの各フォームを表示 -->
{% bootstrap_form articleForm layout='horizontal' %}
<button type='submit' class='btn btn-outline-primary'>作成する</button>
<a href='{% url "bbs:index" %}' class='btn btn-outline-secondary'>戻る</a>
</form>
{% endblock %}
create関数を修正
# myapp/bbs/views.py
def create(request):
if request.method == 'POST':
articleForm = ArticleForm(request.POST) # POSTメソッドならデータを取り出す
if articleForm.is_valid():
article = articleForm.save() # 正常なデータならsaveメソッドで保存
context = {
'message': 'Create article ' + str(article.id),
'article': article,
}
return render(request, 'bbs/detail.html', context)
index.htmlの一覧から/newを呼び出す
<!-- myapp/bbs/templates/bbs/index.html -->
<div>
<a href='{% url "bbs:new" %}' class='btn btn-outline-primary'>新規</a>
</div>
編集フォームの追加
既存の投稿を修正できる編集フォームを作成していきます。
views.pyに「/edit」を追加
# myapp/bbs/views.py
def edit(request, id):
article = get_object_or_404(Article, pk=id)
articleForm = ArticleForm(instance=article) # ArticleFormオブジェクトを生成
context = {
'message': 'Edit Article' + str(id),
'article': article,
'articleForm': articleForm,
}
return render(request, 'bbs/edit.html', context) # edit.htmlテンプレートを呼び出す
edit.htmlを追加
<!-- myapp/bbs/templates/bbs/edit.html -->
{% extends './base.html' %}
{% load bootstrap4 %}
{% block content %}
<h1>{{ message }}</h1>
<!-- 投稿idに合わせたupdateを呼び出す -->
<form action='{% url "bbs:update" article.id %}' method='post' class='form'>
{% csrf_token %}
{% bootstrap_form articleForm layout='horizontal' %}
<button type='submit' class='btn btn-outline-primary'>保存する</button>
<a href='{% url "bbs:detail" article.id %}' class='btn btn-outline-secondary'>戻る</a>
</form>
{% endblock %}
view.pyに「/update」を追加
# myapp/bbs/views.py
def update(request, id):
if request.method == 'POST':
# POSTメソッドなら既存の投稿データを取り出す
article = get_object_or_404(Article, pk=id)
# 受け取ったデータを元にArticleFormオブジェクトを生成
articleForm = ArticleForm(request.POST, instance=article)
if articleForm.is_valid():
articleForm.save() # 正常なデータならデータベースへ格納
context = {
'message': 'Update article ' + str(id),
'article': article,
}
return render(request, 'bbs/detail.html', context) # 詳細ページを呼び出す
detail.htmlから「edit」と「delete」を呼び出す
<!-- myapp/bbs/templates/bbs/detail.html -->
<div>
<a href='{% url "bbs:index" %}' class='btn btn-outline-primary'>一覧</a>
編集
<a href='{% url "bbs:delete" article.id %}' class='btn btn-outline-secondary'>削除</a>
</div>
一覧ページから削除ボタンを除去
<!-- myapp/bbs/templates/bbs/idnex.html -->
<table class='table table-striped table-hover'>
{% for article in articles %}
<tr>
<td>{{ article.content }}</td>
<td>{{ article.user_name }}</td>
<td>
<a href='{% url "bbs:detail" article.id %}' class='btn btn-outline-primary'>詳細</a>
<!-- ここにあった削除ボタンのリンクは削除 -->
</td>
</tr>
{% endfor %}
</table>
