4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DjangoのMetaクラス

Posted at

Metaクラスの役割

  • 使い方は、2パターン
    • モデルクラス内に定義するMetaクラス
    • フォームクラス内に定義するMetaクラス

モデルクラス内のMeta

  • 簡単
  • models.モデル内で定義するMetaクラスは、そのモデルに対して、フィールドを並び替えたり、管理画面で表示されるモデル名を変更したり、各モデルに共通するフィールドをまとめておく(このモデルはDBに反映されない)などといった、そのモデルの関するオプションを設定することができる
    https://note.com/saito_pythonista/n/n2d02442ea1bf#jPuMt

フォームクラス内のMeta

  • 調査に時間がかかった
  • ModelFormやUserCreationForm(ユーザ登録フォーム)を実装するときに使用する
  • ポイントは、FormとModelFormの違いを理解すること
  • model, fieldsの意味
  • ModelForm, UserCreationFormを定義するときに使用する

FormとModelFormの違い

  • 共通部分
    • フォームクラス内に、独自にフィールドを定義すること
      • この場合、独自に定義したフィールドからの入力値はモデルに保存されない
  • Form
    • 入力値のバリデーションを行うのみ
      • フィールドからの入力値は、モデルに保存されない
  • ModelForm
    • 入力値のバリデーション+モデルと連携(指定したモデルの全フィールドを自動で呼び出したり、そのフィールドを通して入力値をモデルに保存するかどうかの設定もできる)
    • Metaクラスを用いてモデルのフィールドを自動で共有することができる(=モデルと連携)
      • model変数:連携するモデルを指定することで、そのモデルの全フィールドをフォームクラス内に自動で定義する(自動生成)
      • fields変数:連携したモデルのどのフィールドをテンプレート上で表示するか。つまり、どのフィールドがユーザからの入力を受け付けるのかを指定する。
      • ここで指定したフィールドは、テンプレート上に表示され、入力を受け付けるため、入力値はmodelで指定したモデルに保存される

具体例(フォームクラス内のMeta)

ユーザ登録フォームを作成するためのフォームクラス、UserCreationFormクラスを使用する場合の具体例を紹介する。

  • 独自に定義したフィールド(UserCreationFormで定義されているフィールド)
    • password1, password2
  • モデルから自動定義したフィールド(実際にフォームに表示するもの)
    • username, email
  • 独自に定義したフィールドとモデルから自動定義したフィールドは、共にフォームをインスタンス化するタイミングで、Context内のformキーの値として格納される(テンプレート上でフォームを表示する具体例については、以下で紹介)

※Djangoは、デフォルトでユーザを保存するためのUserモデルを用意してあるが、独自に作ることを推奨している。そのため、ここでは、AbstractUserクラスを継承した独自のカスタムユーザモデルを定義し、model変数に指定している。
(modelで指定しているCustomuserモデルについては以下で紹介している)

forms.py
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser

class SignUpForm(UserCreationForm):
   # UserCreationFormで定義されているフィールド
    # password1 = forms.CharField(label=_("Password"), strip=False, widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), help_text=password_validation.password_validators_help_text_html())
    # password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), strip=False, help_text=_("Enter the same password as before, for verification."))

    class Meta:
        # model:指定したモデルで定義されている全フィールドを自動で定義する(自動生成)
        model = CustomUser
        # fields:
        # modelで指定したモデルの、どのフィールドをテンプレート上に表示するかを指定する。(モデルのフィールド名を指定する)
        # つまり、指定したフィールドは、ユーザからの入力を受け付けるため、入力値がモデルに保存される
        # フォームクラスで独自に定義したフォームは、ここに書かないこと(混乱の原因)
            # モデルに保存する値かどうかを直感的に判断できなくなる
        # モデルから自動定義したフィールドも独自に定義したフィールドも{{form}}によってテンプレートに表示できる
        fields = ('username', 'email')

混乱するポイント

  • Metaクラス内のfields変数に、フォームクラスで独自に定義したフィールドを指定しないこと
    • 直感的に、どのフィールドが入力値をモデルに保存するのかがわからなくなるため(modelで指定しているモデルをたどればわかるがめんどくさい)
  • fieldsにフォームで独自に定義したフィールドを指定した場合でもエラーなくテンプレート上で表示されてしまう
forms.py
# ダメな例
class Meta:
        model = User
        fields = ('username', 'email', 'is_staff', 'password1', 'password2')

カスタムユーザモデル

  • デフォルトのUserモデルは、AbstractUserクラスを継承して定義されているため、カスタムユーザモデルを定義する時も使用する
  • AbstractUserクラスには、さまざまなフィールドが定義されている
models.py
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass
   # AbstractUserで定義されているフィールド
    # password, last_login
    # is_superuser
    # username, first_name, last_name, email, is_staff, is_active, date_joined, groups, user_permissions

テンプレートでフォームを表示

独自に定義したフィールドもMetaクラスを用いて、モデルから自動で定義したフィールドも共に、formオブジェクト内に格納されているため、そのまま表示することが可能。

  • 自動で定義したフィールドから先に表示される
templates/registration/signup.html
{% extends 'base.html' %}

{% block content %}
<h2>ユーザ登録</h2>
<form method='post'>
    {% csrf_token %}
    {{form.as_p}}
    <button type='submit'>ユーザ登録</button>
</form>
{% endblock %}
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?