95
86

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Django forms.Formを用いたフォームの作成

Posted at

はじめに

 Djangoの初学者はまずDjango公式サイトやDjangogirlsなどのチュートリアルを取り組むのではないか。
 そこで共通するのは、フォームの事例が、forms.ModelFormを利用したものに偏っており、当たり前のようにforms.ModelFormを選択していた。しかし、フォームをオリジナルあるものにするには、forms.Formを使う手があるが、解説した記事が少ないと感じていた。事例を交えて記事に残そうと思う。

環境

Windows10
Python 3.6.0
Django 2.1.1

models.pyの編集

ModelにBookモデルを作成する。タイトル、著者、所有者、貸出先、発刊日、購入日、ISBN、備考を属性として追記する。

models.py
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

フォームの編集

ここでは、本の登録フォームを例とした。

forms.py
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行程度だが、モデルに紐づいているため応用が効きにくい

forms.py
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は省略)

views.py
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は省略

book_new.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 %}

画面はこんなイメージ
new_book.PNG

おわりに

django.forms.ModelFormでforms.pyを作成すると簡単に書くことができるが、モデルと紐づけしないフォームを作成する上で、django.forms.Formでのコーディングは必要となる。

95
86
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
95
86

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?