ユーニックス総合研究所

  • home
  • archives
  • django-model-form

Djangoのformの今どきな作り方【Python, モデルフォーム】

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

Djangoのフォームの作り方

PythonのWebフレームワークである「Django(ジャンゴ)」を使うと簡単にWebアプリを作れます。

Webアプリにはユーザーからの入力を受け付けるフォームがあるのが普通です。
Djangoにも他のWebフレームワークの例にもれずフォームを作るための仕組みがあります。

この記事では今どきなDjangoのフォームの作り方を解説します。
具体的には↓を見ていきます。

  • フォームとは?
  • フォームの必要性
  • forms.pyの作成
  • モデルの定義
  • モデルからフォームを作成する

フォームとは?

Webアプリケーションにおけるフォームとは、ユーザーからの入力を受け付け処理する部品のことです。
この部品はHTMLで記述されます。
HTMLにはforminputなどのタグがあり、これらのタグを使うことでフォームを書くことが出来ます。
その内容は↓のようなものです。

<form action="/" method="POST">  
  <div>  
    <label>名前:</label>  
    <input name="name" type="text" />  
  </div>  
  <div>  
    <label>内容:</label>  
    <textarea name="content"></textarea>  
  </div>  
  <button type="submit">送信</button>  
</form>  

formの仕事は入力された内容をデータとして、特定のページにリクエストを送信することです。
↑のフォームの場合、/に対してPOSTリクエストが送られます。

フォームの必要性

フォームは必要でしょうか?
それは場合によります。
制作しているWebアプリケーションがユーザーからの入力を必要とする場合は、ほとんどの場合フォームが必要です。
動的なWebアプリケーションにおいて、フォームは無くてはならないものです。

たとえば掲示板の場合を考えてみます。
掲示板はユーザーの投稿内容をサイトに表示します。
ユーザーは掲示板にどのように投稿をするのかと言うと、フォームを通じて投稿を行います。

フォームは特定のページにリクエストを行います。
そのリクエストの時に、ユーザーの入力データをいっしょに送ります。
サーバーではその入力データをバリデーションして、場合によってはデータベースを操作します。

動的なWebアプリケーションにおいてフォームはありふれたものです。
そのためWebフレームワークではこのフォームを簡単に作成できる仕組みを提供しています。
Djangoではその仕組みをdjango.formsが提供します。

forms.pyの作成

Djangoでフォームを作成するには、まず最初に自作のフォームを書いておくモジュールを作ります。
慣例的にこのモジュールはforms.pyで作成されます。
forms.pyはアプリケーションの直下に置かれます。

たとえばpython manage.py startapp myappmyappというアプリケーションを作成したとします。
その場合、forms.pymyapp/forms.pyに作成します。

モデルの定義

Djangoのフォームはモデルと連携を取ることが可能になっています。
そのため最初にモデルを作っておきましょう。
今回は掲示板アプリケーションを想定します。

掲示板への投稿内容をPostというモデルで表現することにします。
Postには投稿者名を表すnameと、投稿内容を表すcontentのフィールドを作ります。

from django.db import models  


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

このモデルをフォームで扱ってみたいと思います。

モデルからフォームを作成する

Djangoにはさきほど作成したフォームと密接に連携を行うフォームがあります。
それがdjango.forms.ModelFormです。
このフォームを使うと、フォームにモデルの部品を流用することが可能です。

forms.pyPostFormを作ってみます。

from django import forms  
from .models import Post  


class PostForm(forms.ModelForm):  
    class Meta:  
        model = Post  
        fields = ('name', 'content')  

PostFormはクラスです。
これはdjango.forms.ModelFormを継承します。
こうすることで自作のモデルフォームを作ることが出来ます。

モデルフォームにはMetaという属性をclassで作ります。
その中の属性modelにフォームと連携させたいモデルを指定します。
ここではmodels.Postがそれです。

さらにfields属性にフォーム上で表示させたいフィールド名をタプルで指定します。
↑の例ではmodels.Postのフィールドnamecontentをフォームで表示させるようにしています。

ビューのコンテキストにフォームを設定する

先ほど作成したPostFormをビューで使いたい場合はforms.pyからPostFormをインポートします。
そしてコンテキストにPostFormをオブジェクトにして代入します。

from django.shortcuts import render  
from .forms import PostForm  


def home_view(request):  
    context = {}  

    context['form'] = PostForm()  # <- フォームの代入  

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

こうすることでテンプレートファイルからフォームを使えるようになります。
↑の場合、テンプレートからフォームを使いたい場合はform変数を参照します。

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

先ほど設定したコンテキストを使い、テンプレートでフォームを描画するには、↓のようにform変数を参照します。

<form action="/create/" method="POST">  
  {% csrf_token %}  
  {{ form.as_p }}  
  <button type="submit">送信</button>  
</form>  

🦝 < え! `

`タグは別部品なの?

はい。別部品です。そのため↑のようにフォームの中にform変数を展開するコードになります。
まずフォームでは<form>タグのactionに送信先のパスを指定し、それからmethodにHTTPメソッドを書きます。

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

そしてCSRFトークンをフォーム内に描画します。

{% csrf_token %}  

CSRFトークンとはWebアプリケーションのセキュリティのために設定するトークンです。
DjangoにはCSRFに対処するための仕組みが備わっています。
CSRFトークンについては↓の記事を参照してください。

次にform変数を描画します。

  {{ form.as_p }}  

form.as_pas_pというのはフォームの部品を<p>タグで囲って出力するというものです。
最後に<button>タグでサブミット・ボタンを作ってフォームは終わりです。

  <button type="submit">送信</button>  

フォームからの送信をビューで処理する

さきほど作成したフォームからの送信をビューで処理したいと思います。
フォームのaction/create/になっていましたが、このパスに対応するビューをcreate_view()として作ります。
create_view()の中身は↓のようになります。

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

...  

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

    post = form.save()  

    return HttpResponse(f'{post.id}', status=200)  

django.forms.ModelFormはPOSTされたデータをコンストラクタの引数に取ることが出来ます。

    form = PostForm(request.POST)  

↑のようにすることでPostFormのフィールドをPOSTされたデータで初期化しています。
次にformに設定されたデータが正常かどうかis_valid()メソッドで判定します。

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

↑のif文はformのデータが不正であればHTTPステータスが500HttpResponseを返します。
つまり、POST時にフォームのデータが不正だった場合、ユーザーの画面にはinvalidという文字列が表示されます。

django.forms.ModelFormはセットされたフィールドをモデルに流用することが可能です。
つまりformsave()メソッドを呼び出せばそれだけでモデルを保存することが出来ます。

    post = form.save()  

↑の場合、post変数はmodels.Postのオブジェクトです。
各フィールドはフォームに設定されたデータで初期化されています。
Postオブジェクトを作成したら、最後にそのオブジェクトのIDをHttpResponseで表示して終わりです。

    return HttpResponse(f'{post.id}', status=200)  

HTTPステータスは200で成功になっています。
こうすることで、POSTに成功するとユーザーの画面には作成したオブジェクトのIDが表示されます。

おわりに

Djangoのモデルフォームは便利な代物です。
モデルフォームはDjangoのバージョン1からある歴史のあるフォームです。
便利なのでぜひ使ってみてください。

🦝 < フォームを制する者は動的サイトを制す