質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1868閲覧

UserCreationForm承継時のmodel指定の必要性

wayway

総合スコア11

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/08/22 08:40

編集2020/08/28 09:45

前提・実現したいこと

Python Djangoの初心者です。
YoutubeでCorey Schafer氏のチュートリアルを勉強しています。
https://www.youtube.com/playlist?list=PL-osiE80TeTtoQCKZ03TU5fNfx2UY6U4p

Part 6 - User RegistrationでUserCreationFormを承継したUserRegisterFormを作り、フォームアイテムをカスタマイズする」ための手法を学んでおりますが、そこに関連した質問です。

方法1

djangoの用意したUserCreationFormをそのまま使用する場合は、どこかでmodelの指定を行わずとも動作します。djangoが用意するUserCreationFormクラスの中で、既にmodelの指定が行われていると理解しております。
(コードは下記)

方法2

一方、フォームページに表示される項目を変更したい場合は、forms.pyでUserRegisterFormクラスを作り、UserCreationFormクラスを承継させる方法が紹介されています。

この時、forms.pyでUserRegisterFormを作る際に、modelの指定(model = User)を【行わないと】下記の様なエラーが発生します。
raise ValueError('ModelForm has no model class specified.')
ValueError: ModelForm has no model class specified.

質問

modelの指定が不要なUserCreationFormを承継したUserRegisterFormを使用しているのに、何故その時はmodelの指定が必要になるのでしょうか?

該当のソースコード

(1)UserRegisterFormを使用する場合

<forms.py>

python

1from django import forms 2from django.contrib.auth.models import User 3from django.contrib.auth.forms import UserCreationForm 4 5class UserRegisterForm(UserCreationForm): 6 email = forms.EmailField() 7 8 class Meta: 9 model = User 10 fields = ["username", "email", "password1", "password2"]

<register.html>

python

1{% extends "original_blog/base.html" %} 2{% load crispy_forms_tags %} 3 4{% block content %} 5 <div class="content-section"> 6 <form method = "POST"> 7 {% csrf_token %} 8 <fieldset class="form-group"> 9 <legend class="border-bottom mb-4">登録フォーム</legend> 10 {{ form|crispy }} 11 <div class="form-group"> 12 <button class="btn btn-outline-info" type="submit">登録</button> 13 </div> 14 </fieldset> 15 </form> 16 <div class="border-top pt-3"> 17 <small class="text-muted">既にアカウントを持っている場合はこちらへ<a class="ml-2" href="#">サインイン</small> 18 </div> 19 </div> 20{% endblock content %}

<views.py>

python

1from django.shortcuts import render, redirect 2from django.contrib import messages 3from django.contrib.auth.forms import UserRegisterForm 4 5def register(request): 6 if request.method == "POST": 7 form = UserRegisterForm(request.POST) 8 if form.is_valid(): 9 form.save() 10 username = form.cleaned_data.get("username") 11 messages.success(request, f"{username}さんがユーザー登録されました") 12 return redirect("blog_home") 13 else: 14 form = UserRegisterForm() 15 return render(request, "users/register.html", {'form':form})

(2)UserCreationFormを使用する場合

<register.html>

python

1{% extends "original_blog/base.html" %} 2{% load crispy_forms_tags %} 3 4{% block content %} 5 <div class="content-section"> 6 <form method = "POST"> 7 {% csrf_token %} 8 <fieldset class="form-group"> 9 <legend class="border-bottom mb-4">登録フォーム</legend> 10 {{ form|crispy }} 11 <div class="form-group"> 12 <button class="btn btn-outline-info" type="submit">登録</button> 13 </div> 14 </fieldset> 15 </form> 16 <div class="border-top pt-3"> 17 <small class="text-muted">既にアカウントを持っている場合はこちらへ<a class="ml-2" href="#">サインイン</small> 18 </div> 19 </div> 20{% endblock content %} 21

<views.py>

python

1from django.shortcuts import render, redirect 2from django.contrib import messages 3from .forms import UserRegisterForm 4# from django.contrib.auth.forms import UserCreationForm 5 6 7def register(request): 8 if request.method == "POST": 9 form = UserCreationForm(request.POST) 10 if form.is_valid(): 11 form.save() 12 username = form.cleaned_data.get("username") 13 messages.success(request, f"{username}さんがユーザー登録されました") 14 return redirect("blog_home") 15 else: 16 form = UserCreationForm() 17 return render(request, "users/register.html", {'form':form})

補足情報

Django 3.0.8
Python 3.6.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

この時、forms.pyでUserRegisterFormを作る際に、modelの指定(model = User)を【行わないと】下記の様なエラーが発生します。
raise ValueError('ModelForm has no model class specified.')
ValueError: ModelForm has no model class specified.

理由は、UserRegisterFormで宣言されているMetaクラスにmodelが指定されていないからです。この説明ではエラーメッセージのとおりなのですが、UserRegisterFormのsuperクラスであるUserCreationFormのMetaクラスは、UserRegisterFormでは上書きというか隠されてしまっています。djangoではインスタンス生成時にクラス宣言の内容をチェックしているので、そのチェックに引っかかったということです。

もしsuperクラスのMetaクラスの特性そのものを残したいのであれば、

python

1 class Meta(UserCreationForm.Meta): 2 # model = User 3 fields = ["username", "email", "password1", "password2"] 4

とする必要があります。チュートリアルの筆者は、こうすることが分かりにくいと判断し、あえて継承せず別のクラスとして定義し直したのではないか?と推測します。djangoでは、ModelやModelFormでは、metaclass(動的な型生成)を多用しているようで、クラス宣言(生成)時にその手の情報を構築しているようです。

フォームの継承に関してdjango側での記述は以下のようになっています。

https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#form-inheritance

投稿2020/08/23 19:05

編集2020/08/23 19:06
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wayway

2020/08/23 22:48

>dameo様 回答ありがとうございます! ・原則的にdjangoではMetaクラスはクラス宣言時に構築される ・親クラスのMetaクラスは、子クラスではデフォルトでは承継されない ・Metaクラスも子クラスへ承継させたい場合は、明示的に<親クラス名>.Metaで承継させる必要がある ということ、理解致しました! 大変参考になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問