Djangoのフォーム機能は通常、 django.forms.Form
クラスを継承して定義をします。
フォームを使う | Django ドキュメント | Django
リクエスト時に動的にフォームクラスを生成したい場合もあるので、今回はそれをやってみます。
フォームクラスを動的に生成する関数
myapp/forms.py:
from django import forms def create_form(form_schema_dict): """ 動的にフォームを作成する :form_schema_dict: フォームのスキーマを定義した辞書 :return: フォームクラス 例: form_class = create_form({ "name": {"max_length": 100}, "email": {"max_length": 100}, }) """ form_schema = {} for field_name, options in form_schema_dict.items(): form_schema[field_name] = forms.CharField(label=field_name, **options) return type("DynamicForm", (forms.Form,), form_schema)
この create_form
関数では、指定されたフィールド名とオプションでCharFieldを持つフォームクラスを生成して返します。
type関数は、Pythonの組み込み関数で、引数を3つ指定する場合は、新たな型を生成して返却します。
参考: 組み込み関数 - Python 3.12.3 ドキュメント
動作確認
Django shellからインポートして、フォームクラスが動作するか試します。
>>> from myapp import forms >>> form_class = forms.create_form({ ... 'name': {'max_length': 100}, ... 'email': {'max_length': 100}, ... }) >>> form = form_class() >>> form <DynamicForm bound=False, valid=Unknown, fields=(name;email)>
Djangoのビューで表示してみる
Djangoのビューから呼び出して、テンプレートファイル上でのレンダリングも試します。
myapp/views.py:
from django.shortcuts import render from django import forms from .forms import create_form def index(request): form_class = create_form( { "name": {"max_length": 100}, "email": {"max_length": 100}, "message": {"widget": forms.Textarea}, } ) form = form_class() return render(request, "index.html", {"form": form})
このビュー関数では、単純にフォームを表示するだけにしていますが、やろうと思えば is_valid()
を呼び出してフォーム内容を検証するようなコードにも変更できます。
myapp/templates/index.html:
<html> <head> <title>form test</title> </head> <body> <form> {{ form }} </form> </body> </html>
サンプルコード全体は、GitHubに置いてます。
https://github.com/tokibito/sample_nullpobug/tree/main/django/dynamic-form