ユーニックス総合研究所

  • home
  • archives
  • django-form

Djangoのフォーム(forms.Form)の使い方【Python】

  • 作成日: 2020-12-04
  • 更新日: 2023-12-26
  • カテゴリ: Django

Djangoのフォームの使い方

Django(ジャンゴ)はPythonのWebフレームワークですが、このDjangoにはフォームの制作を助けるためのモジュールがあります。
それがdjango.formsモジュールです。

このモジュールには多数の便利なフォームが置かれています。

今回はこのモジュール内のdjango.forms.Formについて解説します。

このフォームはDjangoのフォームでもっとも基礎的なフォームと言えます。
このフォームよりもモデルとの連携性を高めたフォーム、django.forms.ModelFormもありますが、こちらについては↓の記事をご覧ください。

モデルを作る

今回は適当なアプリとしてmyappを作ってある前提で話します。
アプリについて特別な設定はしていません。
また、掲示板アプリの制作を想定しています。

myapp/models.pyに↓のようにモデルを作ります。

from django.db import models  


class Post(models.Model):  
    name = models.CharField(max_length=64, help_text='投稿者名')  
    content = models.CharField(max_length=1024, help_text='投稿内容')  

Postモデルは掲示板への投稿内容を表すモデルです。
フィールドには投稿者名を表すnameと、投稿内容を表すcontentを作っておきます。

モデルに対応するフォームを作る

ではdjango.forms.Formを使って先ほどのモデルに対応するフォームを作ります。
フォームは慣例的にforms.pyというモジュールに作られるのが一般的です。
今回はmyapp/forms.pyにモジュールを作ります。

↓のようにフォームを作ります。

from django import forms  


class PostForm(forms.Form):  
    name = forms.CharField(max_length=64, help_text='投稿者名')  
    content = forms.CharField(max_length=1024, help_text='投稿内容')  

django.forms.Formを利用するには↑のようにformsをインポートしておきます。
そしてforms.Formを継承したクラスPostFormを作ります。
これはモデルPostのフォームだからPostFormという命名になっています。

フォームを作ったらフォームの中にフィールドを作ります。
モデルに対応するようにnameフィールドとcontentフィールドを作ります。

ここの作りが「2度手間だなぁ」と感じる方はdjango.forms.ModelFormの利用を検討してみてください。

↑のnamecontentなどのフィールドは、フォームを作る際の部品としてHTMLが出力されます。
このときフィールド名は<input>タグのname属性の値になります。
また、フィールドの引数を指定することで<input>タグの属性を変化させることが出来ます。
↑の例ではmax_lengthという引数は<input>タグのmaxlength属性になります。

help_text引数は<input>タグとは別の<span>タグとして出力されます。

フォームを使ってビューを作る

myapp/views.pyにビューを作ります。
今回はhome_view()create_view()を作ります。

home_view()はパス/GETを処理するビューです。
create_view()はパス/create/POSTを処理します。

home_view()ではフォームをユーザーに表示するところをやります。
home_view()の内容ですが、↓のようにします。

from django.shortcuts import render  
from django.http import HttpResponse  # <- create_view()で使う  
from .models import Post  # <- create_view()で使う  
from .forms import PostForm  


def home_view(request):  
    context = {}  

    context['form'] = PostForm()  

    return render(request, 'myapp/home.html', context)  

↑のようにビューのコンテキストにformという変数を作り、先ほど作ったPostFormをオブジェクトにして代入しておきます。
こうすることでテンプレートファイル内からformという変数を参照し、フォームを利用することが出来るようになります。
render()でテンプレートファイルmyapp/home.htmlを描画します。これの実体はmyapp/templates/myapp/home.htmlです。

テンプレートでフォームを描画する

myapp/home.htmlは↓のようになっています。

<form action="/create/" method="POST">  
  {% csrf_token %}  
  {{ form.as_p }}  
  <button type="submit">投稿する</button>  
</form>  

このテンプレートではユーザーにフォームを表示します。
ユーザーはこのフォームに入力を行い、投稿ボタンを押して掲示板に投稿するという想定です。

意外に思われるかもしれませんが、↑のようにDjangoのフォームは<form>タグ自体を描画しません。
ですので<form>タグは自分で書く必要があります。

最初に<form>タグを書きます。

<form action="/create/" method="POST">  

actionにはフォームの送信先のパスを指定します。これは{% url ... %}を使っても大丈夫です。今回は解説の簡便さのために直書きしています。
methodにはフォームが送信するリクエストのメソッドを指定します。このフォームが送信するリクエストはデータベースに変更を加えるリクエストなのでPOSTを指定します。

次にCSRFトークンを描画します。

  {% csrf_token %}  

↑のようにすることでCSRFトークンが記述された<input>タグを出力できます。
CSRFトークンとはWebアプリケーションのセキュリティを高めるトークンです。
これはCSRF攻撃を防御します。
CSRF攻撃に対して無力なWebアプリケーションはネットに公開しては駄目です。
CSRFについては詳しくは↓の記事をご覧ください。

次にフォームのフィールドをHTMLとして出力します。

  {{ form.as_p }}  

↑のようにformを参照するとHTMLを出力することが出来ます。
おしりについてるas_pというのは、フォーム内のフィールドを<p>タグで囲って出力するという意味になります。
↑の出力を見ると<input>タグが<p>タグで囲われて出力されているのがわかります。

最後に投稿ボタンを配置します。

  <button type="submit">投稿する</button>  

これでフォームの描画は完了です。
アプリの/にアクセスすると↓のようなフォームが表示されます。

フォームからのリクエストを処理する

再びmyapp/views.pyに戻ります。
次はcreate_view()を作ります。
このビューはパス/create/に対応していて、先ほど作ったフォームからのリクエストを処理するビューです。
create_view()は↓のように作っておきます。

from django.shortcuts import render  
from django.http import HttpResponse  
from .models import Post  
from .forms import PostForm  


...  


def create_view(request):  
    form = PostForm(request.POST)  
    if not form.is_valid():  
        return HttpResponse('invalid', status=500)  

    name = form.cleaned_data['name']  
    content = form.cleaned_data['content']  

    post = Post.objects.create(name=name, content=content)  

    return HttpResponse(f'{post.id}')  

まず↓の部分です。

    form = PostForm(request.POST)  

request.POSTにはPOSTされたデータ、つまりnamecontentなどのデータが入っています。
fomrs.Formはコンストラクタの引数にrequest.POSTを指定すると、そのrequest.POSTのデータでフィールドを初期化します。
つまりこの段階でform変数内のフィールドにはデータがセットされているわけです。

次に↓の部分です。

    if not form.is_valid():  
        return HttpResponse('invalid', status=500)  

フォームにはデータをバリデーション(検証)する仕組みがあります。
バリデーションと言うのは、データが不正かどうかチェックする機能のことです。
ソフトウェア開発においては基本的に、第3者からの入力と言うのはいっさい信用してはいけないというのが共通認識になってます。

そのため↑のようis_valid()メソッドを呼び出してバリデーションを行います。
is_valid()はフォームにセットされているデータが不正であればFalseを返し、不正でなければTrueを返します。
不正の場合はHttpResponseでユーザーの画面にinvalidと表示させ、処理を中断します。

次に↓の部分です。

    name = form.cleaned_data['name']  
    content = form.cleaned_data['content']  

フォームでバリデーションされたデータはフォームのcleaned_dataという辞書に保存されます。
このcleaned_dataを参照することでユーザーの入力したデータ(バリデーション済み)にアクセスすることが可能です。
↑の場合、cleaned_dataからnamecontentのフィールドの値を変数に保存しています。

次に↓の部分です。

    post = Post.objects.create(name=name, content=content)  

↑ではフォームのフィールドの値を使ってPostオブジェクトを作成しています。
そして最後に↓の部分でユーザーの画面に、作成したPostオブジェクトのIDを表示します。

    return HttpResponse(f'{post.id}')  

このビューを作ってからフォームにデータを入力して送信ボタンを押すと、画面にPostオブジェクトのIDが表示されるようになります。

おわりに

今回はdjango.forms.Formを解説しました。
このフォームは柔軟な設定が可能なので、知っておくと使う機会があるかもしれません。
ほとんどの場合django.forms.ModelFormで用は足りるとは思いますが。

🦝 < アディオス、カウボーイ

関連記事