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

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

ただいまの
回答率

88.36%

クラスベース汎用ビュー(FormView)内でフォームクラスに括弧をつけて初期値を指定すると"not callable"エラーになる

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 808

k-zil

score 16

前提・実現したいこと

pythonのフレームワークDjangoでシステムを構築中です。
form.pyのFormクラスで定義したフォームの初期値をビューから指定したいと思い、以下のページなどを参考にして、ビューのコードを書き換えたのですが、'EntryForm' object is not callableというエラーでDjangoに怒られてしまいます。

  1. https://qiita.com/sapuri/items/f6fb992334b6afb6196e
  2. http://i2bskn.hateblo.jp/entry/20120826/1345936779

上記のページと自分のコードの差は、ビューが関数で書かれているかクラス(クラスベース汎用ビューFormView)で書かれているかという点だろうと推測していろいろ調べた結果、最終的には、ビュー内でget_initialメソッドをオーバーライドすることで初期値を指定することに成功はしたのですが、上記の参考ページのように、ビュー内でフォームクラス(クラス名EntryForm)に括弧をつけて値を指定する方法だと、なぜnot callableになるのかが分かりません。

'クラス'、'メソッド'、'関数'の基礎的知識が不足しているためだと思いますが、この戸惑いについて腹に落ちる解説、または参考ペーシを教えていただけますと幸いです。
あやふやな理解のまま開発を進めると、また同じような躓きで時間を取られそうで怖いので、一度きちんと理解したく、その手立てをご指南いただけると助かります。
どうかよろしくお願い致します。

該当のソースコード

#forms.py
class EntryForm(forms.Form):
    name = forms.CharField(
        max_length = 200,
        initial = u'鈴木太郎', # 初期値
    )
#views.py
#変更前のビュー
class EntryInput(FormView):
    form_class = EntryForm
    template_name = "entry_input.html"

これを以下のように変更しました。(EntryFormに括弧をつけて初期値を指定。)

#views.py
#変更後のビュー(1)
class EntryInput(FormView):
    form_class = EntryForm( initial = {'name': u'佐藤次郎'} )
    template_name = "entry_input.html"

すると'EntryForm' object is not callableのエラーになります。

なお、以下のようのようにEntryFormの後ろに括弧を付けただけでも同じエラーになります。

#views.py
#変更後のビュー(2)
class EntryInput(FormView):
    form_class = EntryForm()
    template_name = "entry_input.html"

いろいろ調べて、最終的には、

#views.py
#変更後のビュー(3)
class EntryInput(FormView):
    form_class = EntryForm
    template_name = "entry_input.html"

    def get_initial(self):
        initial = super().get_initial()
        initial["name"] =  u'佐藤次郎'
        return initial

とすることで初期値を変更できました。

※最終的に参考にさせてもらったサイトは以下です。

  1. https://qiita.com/maisuto/items/33dfeb58f5953d1c5fdf#クラスベース汎用viewとの連携
  2. https://canon1ky.hatenablog.com/entry/2018/11/17/131128

知りたいこと

知りたいことは、なぜ変更後のビュー(1)や(2)では'EntryForm' object is not callableのエラーになってしまうのか、です。どうかご指南をよろしくお願い致します。

補足情報(FW/ツールのバージョンなど)

サーバ:さくらVPS(centOS 7.5)
Python:3.6.5
Django :2.1

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

EntryFormはクラスオブジェクト、EntryForm()EntryFormクラスのインスタンスです。クラスをcallするとインスタンス化されるという仕組みです。

後ろの処理でform_classがクラスオブジェクトであることを期待してcallしている部分があったとします(フレームワークの内部かもしれませんが)。form_classにインスタンスを代入してしまうと、インスタンスに対するcallを試みて、'EntryForm' object is not callableになります。
(一般的なインスタンスは呼び出すことができません。特殊メソッド__call__を実装すればその限りではないが、こういうケースで使うものではない。念の為)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/23 15:58 編集

    hayataka2049様
    ご回答ありがとうございました。返信コメントでは文章がうまく装飾できなかったので回答の追加という形で返信させていただきました。お手数ですがどうぞよろしくお願い致します。

    キャンセル

0

hayataka2049様
ご回答ありがとうございました。せっかくヒントをいただいておきながら心苦しいのですが、今ひとつ理解できません。
すみません。質問の仕方を変えてみます。

元々viewを以下のようにしていました。

#views.py
#クラスベースビュー
class EntryInput(FormView):
    form_class = EntryForm( initial = {'name': u'佐藤次郎'} )
    template_name = "entry_input.html"

これだと元々に質問のとおり、'EntryForm' object is not callableのエラーになります。(EntryFormの後ろの括弧をなくせばエラーはなくなります)

次にこれを以下のように関数ベースビューにしてみました。

#views.py
#関数ベースビューに変更してみた(urls.py内の記述ももちろん少し修正した)
def EntryInput(FormView):
    form_class = EntryForm( initial = {'name': u'佐藤次郎'} )
    return render(request, 'entry_input.html', {'form': form_class} )


こうするとエラーは出ずに動作します。

前者のクラスベースビューの中でEntryFormに括弧をつけるとエラーになり、後者の関数ベースビューの中でEntryFormに括弧つけてもエラーにならない。この差は何なんでしょうか??
どのあたりの知識を習得すれば上記の疑問が解決できるのかご指南いただけますと助かります。
何卒よろしくお願い致します。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/24 02:44

    クラスベースビューだとform_classはクラス変数になり、その後の処理では、クラスが代入されていてインスタンスすることができる前提で扱われます。
    関数ベースビューではform_classは関数のローカル変数であり、外部からは見えません。この名前である必要性もありません。変数を作らなくても構いません。
    a = EntryForm( initial = {'name': u'佐藤次郎'} )
    return render(request, 'entry_input.html', {'form': a} )
    とか
    return render(request, 'entry_input.html', {'form': EntryForm( initial = {'name': u'佐藤次郎'} )} )
    で動くということです。

    見た目は少しだけ似ていますが、まったく別の仕組みで動いていると理解してください。

    キャンセル

  • 2019/04/24 02:45 編集

    より深く理解するためには、まずクラスや関数などのpythonの基本的な機能についてしっかり理解してください。その上で、エラーメッセージのtracebackを見て、どこでエラーになっているのかを確認する(django内部の動作までコードを追って把握していく)ことが理解の助けになると思います。

    キャンセル

  • 2019/05/05 13:12

    hayataka2049様
    いただいた回答を何度も読み返し、いろいろと調べた結果、ようやく問題の本質が理解できました。
    最初の回答でご指摘いただいたとおり、djangoの内部(django.views.generic.editのFormMixin)で、form_classをクラスオブジェクトであると期待してcallしている部分がありました。
    djangoのエラーメッセージのTracebackでもその部分が問題の箇所としてちゃんと明示されておりました。

    今回の失敗は、
    ・form_classが特別な変数である(クラス継承元の中でクラスオブジェクトとして扱われる)ということに全く意識が行かなった
    ・Traceback等で指摘されたエラー内容をきちんと理解していなかった

    今回のエラーになった際、EntryFormの後に括弧を付けてみた箇所がTracebackでは明示されないことを不思議に思っていました。
    問題はそこではなく、hayataka2049様の仰るとおり、その後の処理におけるform_class変数の扱いに注意を向けるべきでした。

    今思えば最初にいただいた回答のとおりでした。
    大変勉強になりました。
    今後は恐れずTracebackで指摘された箇所をdjango内部まで追って理解するようにしたいと思います。
    ありがとうございました!

    キャンセル

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

  • ただいまの回答率 88.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Pythonに関する質問
  • クラスベース汎用ビュー(FormView)内でフォームクラスに括弧をつけて初期値を指定すると"not callable"エラーになる