ユーニックス総合研究所

  • home
  • archives
  • django-form-get-val

DjangoのFormの値の取得方法: is_validとcleaned_data

  • 作成日: 2021-08-22
  • 更新日: 2023-12-26
  • カテゴリ: Django

DjangoのFormの値の取得方法

DjangoではHTMLで書かれるフォームをFormオブジェクトに抽象化して扱うことが出来ます。
Formオブジェクトにした場合、フォームのデータのやり取りはこのFormオブジェクトを通して行われます。

この記事ではFormから、フォームに入力された値(情報)を取得する方法を詳しく解説します。
結論から言うとFormから値を取得するにはFormの属性cleaned_dataを参照します。

    title = form.cleaned_data['title']  

cleaned_dataの参照ではFormのis_validメソッドの知識も合わせて必要になりますので、この記事で解説します。
具体的には↓について見ていきます。

  • Formのデータを取得するおおまかな流れ
  • 前提とするプロジェクトとアプリ
  • 前提とするForm
  • 前提とする関連モジュール
  • POSTデータをFormにセットする
  • cleaned_dataでFormからデータを取得する

関連記事
Djangoのフォーム(forms.Form)の使い方【Python】
Djangoのformの今どきな作り方【Python, モデルフォーム】
DjangoのFormの初期値の設定方法: initial属性の使い方

参考
フォームを使う | Django ドキュメント | Django
フォームとフィールドの検証 | Django ドキュメント | Django

Formのデータを取得するおおまかな流れ

Formからデータを取得する大まかな流れについて解説します。
データの取得の流れはだいたい↓のようなものです。

  • ビューでGETを処理する
  • GETに応じたフォームを描画する
  • ユーザーがフォームに入力しPOSTで送信する
  • ビューでPOSTを処理する
  • POSTのデータをフォームに渡してバリデーションをする
  • バリデーション済みのデータをフォームから取得する

というのがFormのデータを取得する大まかな流れになります。
つまりFormに格納されるデータというのはPOSTのデータなんですね。
そしてそのPOSTのデータがフォームでバリデーションされて、そのバリデーションされたデータをcleaned_dataで取得すると言う感じになります。

今回の解説ではGETでフォームを描画する所から解説します。

前提とするプロジェクトとアプリ

前提として、解説用に作成しているDjangoのプロジェクトはmysiteという名前になります。
それからmyappというアプリを作成済みです。

前提とするForm

まず前提とするFormですが、今回は本をテーマにフォームを定義したいと思います。
本のタイトルと説明を格納するフォームBookFormを作ります。
このBookFormmyapp/forms.pyに保存しておきます。

# myapp/forms.py  
from django import forms  


class BookForm(forms.Form):  
    title = forms.CharField(  
        label='本のタイトル',  
        max_length=100,  
        required=True,  
        help_text='必須',  
    )  
    description = forms.CharField(  
        label='本の説明文',  
        widget=forms.Textarea,  
        required=False,  
        help_text='*任意',  
    )  

BookFormtitledescriptionの2つの属性を持つシンプルなフォームです。

前提とする関連モジュール

関連モジュールとしてまずmysite/urls.pyは↓のようになっています。

# mysite/urls.py  
from django.contrib import admin  
from django.urls import path  
from myapp.views import home  

urlpatterns = [  
    path('admin/', admin.site.urls),  
    path('', home, name='myapp_home'),  
]  

今回は手抜きでアプリではなくmysite(プロジェクト)のほうのurls.pyにルート情報を書いています。
myapp.viewshomeビューはインデックス用のビューになります。

それからmyapp/views.pyは↓のように定義しています。

# myapp/views.py  
from django.shortcuts import render  
from django.http import HttpResponse  
from myapp.forms import BookForm  


def home(request):  
    # GETメソッドを処理する  
    if request.method == 'GET':  
        form = BookForm()  # フォームを作成して  
        context = { 'form': form }  # コンテキストに保存して  
        return render(request, 'myapp/home.html', context)  # 描画  

    # POSTメソッドを処理する  
    elif request.method == 'POST':  
        form = BookForm(request.POST)  # POSTデータをフォームに保存する  
        if not form.is_valid():  # バリデーションを行う  
            # データが不正だったらフォームを再描画する  
            context = { 'form': form }  
            return render(request, 'myapp/home.html', context)  

        # ↓がフォームから値を取得している所  
        title = form.cleaned_data['title']  
        description = form.cleaned_data['description']  

        # 値を元にレスポンスを生成する  
        return HttpResponse(f'{title}: {description}')  

    # 未対応のメソッド  
    else:  
        return HttpResponse('不正なメソッドです', status=500)  

このmyapp/views.pyが今回の解説の本丸となるところです。
これについて後述で詳しく見ていきます。

それからテンプレートファイルmyapp/templates/myapp/home.htmlは↓のようになっています。

{# myapp/templates/myapp/home.html #}  

<h1>本の情報登録フォーム</h1>  

<form action="{% url 'myapp_home' %}" method='POST'>  
  {% csrf_token %}  
  {{ form.as_p }}  
  <input type="submit" value="登録" />  
</form>  

こちらのテンプレートファイルではフォームを描画しています。
フォームのアクションは先ほどのhomeビューへのルートを指定します。
methodPOSTです。

これまでのビューとテンプレートを描画すると↓のような画面になります。

POSTデータをFormにセットする

肝心のmyapp/views.pyについて詳しく見ていきます。
まずhomeビュー内ではメソッドを処理して分岐しています。

def home(request):  
    # GETメソッドを処理する  
    if request.method == 'GET':  
        ...  

    # POSTメソッドを処理する  
    elif request.method == 'POST':  
        ....  

    # 未対応のメソッド  
    else:  
        ....  

request.methodGETの場合とPOSTの場合とで処理を分岐しています。
POSTメソッド内の処理を見てみます。

    # POSTメソッドを処理する  
    elif request.method == 'POST':  
        form = BookForm(request.POST)  # POSTデータをフォームに保存する  
        if not form.is_valid():  # バリデーションを行う  
            # データが不正だったらフォームを再描画する  
            context = { 'form': form }  
            return render(request, 'myapp/home.html', context)  

        # ↓がフォームから値を取得している所  
        title = form.cleaned_data['title']  
        description = form.cleaned_data['description']  

        # 値を元にレスポンスを生成する  
        return HttpResponse(f'{title}: {description}')  

POSTメソッドの場合、request.POSTに送信されたデータが格納されています。
request.POSTPOSTは辞書に似たデータ構造です。
この辞書をBookFormのコンストラクタ(初期化関数)に渡します。

        form = BookForm(request.POST)  # POSTデータをフォームに保存する  

こうすることでrequest.POSTのデータを持ったフォームを作ることが可能です。
あとはこのフォームのis_valid()メソッドを呼び出して、フォーム内のデータをバリデーションさせます。
is_valid()Trueであればフォーム内のデータは正常で、Falseであれば異常になります。

is_validは内部ではerrors属性を参照しています。
errors属性はプロパティで、このプロパティを参照したときにフォームのfull_clean()メソッドが実行されます。
full_clean()は各種フィールドやフォームのバリデーションを一括で行っています。

is_valid()Falseの場合は適当にHttpResponseを生成してユーザーに不正なデータであることを通知します。

        if not form.is_valid():  # バリデーションを行う  
            # データが不正だったらフォームを再描画する  
            context = { 'form': form }  
            return render(request, 'myapp/home.html', context)  

cleaned_dataでFormからデータを取得する

フォームのデータが正常であればフォームの属性cleaned_dataを参照してフォーム内に保存されているデータを取得します。
cleaned_dataは辞書のようなオブジェクトで、辞書のように扱うことが出来ます。

        # ↓がフォームから値を取得している所  
        title = form.cleaned_data['title']  
        description = form.cleaned_data['description']  

あとは適当にフォームの値を使ってレスポンスを生成します。

        # 値を元にレスポンスを生成する  
        return HttpResponse(f'{title}: {description}')  

今回はレスポンスの生成はHttpResponseを使って手抜きしていますが、もちろんrender()などを使ってもOKです。

おわりに

今回はDjangoのFormの値の取得方法を見てみました。
フォームを使えばバリデーションなども簡単に行えますし、値の取得も手軽に行えます。
Djangoのフォームに慣れてしまえば色々手っ取り早くコードを書くことも出来るので、至れり尽くせりと言う感じですね。

🦝 < 笑顔をフォームする

🐭 < いい笑顔だ