Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
78
Help us understand the problem. What is going on with this article?
@peijipe

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

More than 1 year has passed since last update.

はじめに

 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でのコーディングは必要となる。

78
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
peijipe
python,djangoを中心にメモを残していきます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
78
Help us understand the problem. What is going on with this article?