##この記事について
Djangoにはモデル定義から動的に画面(HTML)を生成するClass Based Viewという仕組みがあります。
Class Based View で入力フォームを出力すると、モデルのフィールドに対応するバリデーション機能とエラー表示(日本語対応)が暗黙的に追加されます。さらに表示をBootstrapに対応させる追加パッケージ Django-Crispy-Forms を組み合わせることでフォーム作成の作業が大幅に簡略化されます。
他のフレームワークのスキャフォールディングに近い役割ですが、オプション設定を行うフォームクラスを追加して細かい調節ができるので自由度は高いです。
この記事では、入力フォームの作り方の要点をまとめました。
本当に要点のみなので、詳しい点についてはリンク先の参考サイトを見てください。
##サンプルイメージ
class Item(models.Model):
name = models.CharField(max_length=50, verbose_name="名前")
age = models.IntegerField(verbose_name="年齢")
memo = models.TextField(max_length=200, verbose_name="備考")
is_checked = models.BooleanField(verbose_name="確認済み")
check_date = models.DateField(verbose_name="確認日")
上記のコードで以下の赤線部分が生成される。
バリデーションとエラーメッセージは日付フィールドに合わせて自動的に設定されたものが使われる。
##作成方法
###1.Modelを定義する
####1-1.フィールド
まずDjangoの一般的な方法で、models.pyにModelを定義しフィールドを追加します。
フィールドの型に合わせて出力されるHTMLのinputタグのtype属性が決まります。
フィールドの種類の例
|扱う型|フィールド|input type|
|:--|:--|:--|:--|
|文字列|CharField|text|
|長い文字列|TextField|textareaタグ|
|数値|IntegerField|number|
|ブール値|BooleanField|checkbox|
Djangoにはこの他にも大量のフィールドクラスが用意されています。
フィールドによってはmin・max属性などが追加されるものもあります。
IntegerRangeFieldなど、Postgres専用の型もあります。
詳しくは公式サイトを参照してください。
https://docs.djangoproject.com/ja/2.0/ref/models/fields/
https://docs.djangoproject.com/ja/2.0/ref/contrib/postgres/fields/
選択リストの作り方
フィールドの「choice」オプションを設定することでinput typeがSelectになります。
class Item(models.Model):
YEAR_CHOICES = (
(10, '10代'),
(20, '20代'),
(30, '30代'),
(40, '40代'),
)
age = models.IntegerField(verbose_name="年齢", choices=YEAR_CHOICES)
後述するModelFormクラスでwidgetオプションを設定することにより、ラジオボタンに変更することも可能です。
####1-2.バリデーション
バリデーションは、まずフィールドに合わせた型チェックが行われ、blankオプションの有無にもとづいて必須チェックが適用されます。そのほか以下のようなバリデーションクラスを追加することができます。
バリデーションクラスの例:
検証内容 | バリデーションクラス |
---|---|
正規表現によるチェック | RegexValidator |
最小文字数 | MinLengthValidator |
最大文字数 | MaxLengthValidator |
最小値 | MinValueValidator |
最大値 | MaxValueValidator |
サンプルコード
class Item(models.Model):
name = models.CharField(
max_length=50,
verbose_name="名前",
validators=[validators.RegexValidator(
regex=u'^[ぁ-んァ-ヶー一-龠]+\u3000[ぁ-んァ-ヶー一-龠]+$',
message='氏名は漢字・ひらがな・カタカナのみとし、氏と名の間に全角スペースを入れてください',
)]
)
age = models.IntegerField(
verbose_name="年齢",
validators=[validators.MinValueValidator(1)])
check_date = models.DateField(
verbose_name="確認日",
validators=[validators.MaxValueValidator(
date.today(),
message='本日以前の日付を入力してください',
)],
)
結果
###2.ModelFormを定義する
以下のようにViewを記述することでModelクラスだけでClass Based Viewによる入力フォームが利用できます。
from django.views.generic.edit import CreateView
class ItemCreateView(CreateView):
model = Item
fields = '__all__' #実際は必要なフィールドのみを選択する
しかし、Modelの定義のみでは以下のような細かい要件に対応できません。
・Selectリストではなくradioボタンを使う。
・入力画面と変更画面で編集可項目を変える。
・placeholderやclassなどの属性を追加する
そのような場合はModelFormクラスを別途定義します。
以下の例ではプレースホルダの追加と、選択リストからラジオボタンへの変更をしています。
サンプルコード
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ("__all__")
widgets = {
"name": forms.TextInput(attrs={'placeholder':'紀伊 太郎'}),
"age": forms.RadioSelect(),
}
class ItemCreateView(CreateView):
model = Item
form_class = ItemForm
フォームのフィールドも多くの種類が用意されています。公式のページを参考にしてください。
https://docs.djangoproject.com/ja/2.0/ref/forms/fields/
3.templeteに埋め込む
あとはテンプレートにフォームタグを埋めこむだけです。
Django-Crispy-Formsを使うとcontrol-group まわりのタグが自動的に付与されるので、Bootstrapでの利用が簡単になります。
Django-Crispy-Forms 設定等は以下のエントリが参考になります。
サンプル
<!-- -->
{% extends "./base.html" %}
<!-- -->
{% load crispy_forms_tags %}
<!-- -->
{% block content %}
{{ form.certifications.errors }}
<div class="container">
<div class="row">
<div class="col-12">
<h1>入力画面</h1>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="float-right">
<a class="btn btn-outline-secondary" href="{% url 'index' %}">戻る</a>
<button type="submit" class="btn btn-outline-secondary" form="myform">保存</button>
</div>
</div>
</div>
<!-- -->
<div class="row">
<div class="col-12">
<form method="post" id="myform">
{%crispy form%}
</form>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="float-right">
<a class="btn btn-outline-secondary" href="{% url 'index' %}">戻る</a>
<button type="submit" class="btn btn-outline-secondary" form="myform">保存</button>
</div>
</div>
</div>
</div>
<!-- -->
{% endblock %}
Crispy-Formsの利用には、別途事前にBootstrapを読み込む必要があります。
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- Required meta tags always come first -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>サンプルアプリ</title>
<!-- Bootstrap CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<!-- -->
{% block content %}
<!-- -->
{% endblock %}
<!-- jQuery first, then Tether, then Bootstrap JS. -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
</body>
</html>