はじめに
Djangoの初学者はまずDjango公式サイトやDjangogirlsなどのチュートリアルを取り組むのではないか。
そこで共通するのは、フォームの事例が、forms.ModelFormを利用したものに偏っており、当たり前のようにforms.ModelFormを選択していた。しかし、フォームをオリジナルあるものにするには、forms.Formを使う手があるが、解説した記事が少ないと感じていた。事例を交えて記事に残そうと思う。
環境
Windows10
Python 3.6.0
Django 2.1.1
models.pyの編集
ModelにBookモデルを作成する。タイトル、著者、所有者、貸出先、発刊日、購入日、ISBN、備考を属性として追記する。
from django.db import models
class Book(models.Model):
LIBRARY_CHOICES = (
('国立図書館', '国立図書館'),
('県立図書館', '県立図書館'),
('市立図書館', '市立図書館'),
)
title = models.CharField(max_length=200)
author = models.CharField(max_length=50)
holder = models.CharField(max_length=10, choices=LIBRARY_CHOICES)
user = models.CharField(max_length=50, default='admin')
published_date = models.DateField(blank=True, null=True)
purchased_date = models.DateField(blank=True, null=True)
isbn = models.BigIntegerField()
comment = models.TextField(blank=True, null=True)
def __str__(self):
return self.title
フォームの編集
ここでは、本の登録フォームを例とした。
from django import forms
LIBRARIES_CHOICES = (
('国立図書館', '国立図書館'),
('県立図書館', '県立図書館'),
('市立図書館', '市立図書館'),
)
class BooksForm(forms.Form):
title = forms.CharField(
label='タイトル',
max_length=200,
required=True,
)
author = forms.CharField(
label='著者',
max_length=50,
required=True,
)
holder = forms.ChoiceField(
label='所有者',
widget=forms.Select,
choices=LIBRARIES_CHOICES,
required=True,
)
user = forms.CharField(
label='貸出先',
max_length=50,
required=True,
)
published_date = forms.DateTimeField(
label='発刊日',
required=True,
widget=forms.DateInput(attrs={"type": "date"}),
input_formats=['%Y-%m-%d']
)
purchased_date = forms.DateTimeField(
label='購入日',
required=True,
widget=forms.DateInput(attrs={"type": "date"}),
input_formats=['%Y-%m-%d']
)
# 日付だけでなく、日時にする場合は以下
# datetime = forms.DateTimeField(
# label='日時',
# required=True,
# widget=forms.DateTimeInput(attrs={"type": "datetime-local"}),
# input_formats=['%Y-%m-%dT%H:%M']
#)
isbn = forms.IntegerField(
label='isbn',
required=False,
)
comment = forms.CharField(
label='備考',
max_length=1000,
required=False,
widget=forms.TextInput()
)
django.forms.ModelFormでforms.pyを作成すると、forms.ModelFormを利用すると以下4行程度だが、モデルに紐づいているため応用が効きにくい
from django import forms
from .models import Book
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title', 'author')
コントローラ(Views)の編集
本の登録を行うコントローラを関数ベースで定義する。
フォームからPOSTがなければ、formをそのままbook_new.htmlに渡す。
フォームに入力があり、POSTを送信した場合、入力内容をバリデートする。バリデートが通った場合、bookオブジェクトをcreateする。
その後、本一覧ページにredirectしている。(redirect先である、book_list.htmlは省略)
from django.shortcuts import render, get_object_or_404, redirect
from .models import Book
from .forms import BooksForm
def book_new(request):
form = BooksForm(request.POST or None)
if form.is_valid():
book = Book()
book.title = form.cleaned_data['title']
book.author = form.cleaned_data['author']
book.holder = form.cleaned_data['holder']
book.user = form.cleaned_data['user']
book.published_date = form.cleaned_data['published_date']
book.purchased_date = form.cleaned_data['purchased_date']
book.isbn = form.cleaned_data['isbn']
book.comment = form.cleaned_data['comment']
Book.objects.create(
title=book.title,
author=book.author,
holder=book.holder,
user=book.user,
published_date=book.published_date,
purchased_date=book.purchased_date,
isbn=book.isbn,
comment=book.comment,
)
return redirect('book:book_list')
return render(request, 'book/book_new.html', {'form': form})
テンプレートの編集
本の登録を行うテンプレートを準備
※継承元のテンプレートbook/base.htmlは省略
{% extends 'book/base.html' %}
{% block content %}
<h1>New book</h1>
<table class="table">
<form method="post" action="">
{% csrf_token %}
<tbody>
<tr>
<th>タイトル</th>
<td>{{ form.title }}</td>
</tr>
<tr>
<th>著者</th>
<td>{{ form.author }}</td>
</tr>
<tr>
<th>所有者</th>
<td>{{ form.holder }}</td>
</tr>
<tr>
<th>貸出先</th>
<td>{{ form.user }}</td>
</tr>
<tr>
<th>発刊日</th>
<td>{{ form.published_date }}</td>
</tr>
<tr>
<th>購入日</th>
<td>{{ form.purchased_date }}</td>
</tr>
<tr>
<th>ISBN</th>
<td>{{ form.isbn }}</td>
</tr>
<tr>
<th>備考</th>
<td>{{ form.comment }}</td>
</tr>
</tbody>
<tr>
<td><input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-secondary" type="reset" value="Reset">
</td>
<td>
</td>
</tr>
</form>
</table>
{% endblock %}
おわりに
django.forms.ModelFormでforms.pyを作成すると簡単に書くことができるが、モデルと紐づけしないフォームを作成する上で、django.forms.Formでのコーディングは必要となる。