Django:CRUDを実装する【detail-update】DBの詳細表示と更新

Django:CRUDを実装する【detail-update】DBの詳細表示と更新

Django:CRUDを実装する【detail-update】DBの詳細表示と更新

このパーツは多くの教本で「forms.pyを使ってTemplateで呼び出しましょう」という構成になっています。
確かにそっちの方が楽なんですけど、楽である以上なにがしかの不具合もあったりします。
forms.pyを使った時の具体的な問題点は『デザイン周り』です。
なので、ゴリゴリな方法も覚えておいて損はないかと思っています。

プリセットクラスを利用した詳細表示の記載方法

PresetClassは汎用ビューという呼ばれ方しているようですね。
この名称で検索した方が沢山の事例に出会えます。

(個人的に)面倒だと感じたのは【DetailView】【UpdateView】という2つが存在する事です。
Laravelと比較してみると参考にさせて頂いた情報ではこんな感じでした。

  • Laravel の edit 相当 = UpdateView
  • Laravel の show 相当 = DetaliView

そんなところを考慮しながらプリセットClassのScriptを見てみます。

■app/urls.py

■app/models.py

■app/views.py

■app/template/hoge_detail.html

■app/template/hoge_update.html

LaravelでのShowの扱いと同じですね、detail要らなくね?

PresetClass(汎用ビュー)を利用する場合の問題点

以下は私の詰まった点です。やり方はあるので知見のある方は難なくクリアできると思います。

  1. update成功時のリダイレクト先(success_url)にページネーションのあるListを設定する
  2. Template.html で呼び出す {{ form }} でレスポンシブデザインを作る
  3. update時のバリデーションエラーが発生する

特に[1]と[3]で沼りました。

update成功時のredirect先にページネーションを付ける方法

こんな形でClass内で関数を呼び出すとreverse関数を使えます。

reverse_lazyに対してpkを渡すとエラー。関数宣言をせずにreverse関数を使ってもImproperlyConfigurというエラーが返ってきます。クラス変数を設定する段階ではURLConf(=urls.py)をまだ読み込んでいない為に怒られているそうで、GET値を含めたページ指定は関数宣言をして処理を書く必要があります。

update時のバリデーションエラー

私の場合の原因は日付DATAとNULLで登録たい数値カラムでの’None’が原因でした。
特に日付についてはHTML5のDateTypeを使ってPOSTしたのですが、この送った日付がバリデーションエラーを出してました。

これは {{ Form }} として呼び出している場合には多分発生しない現象だと思います。
forms.pyでページ構成まで作成する方法についてはHTMLに慣れている私からするとちょっと面倒。
なので、forms.pyにはフィールド構成だけ載せていたのですが、こういう使い方が仇になったようです。

回避方法としては2通りあります。

  1. Template側でPOSTする前に撥ねられない形に整える。
  2. updateにforms.pyを参照しない ※必然的に汎用ビューを使わない方法(def 書出し)になります。

関数(def)を使ってUpdateを書く

PresetClassを使わない場合、Views.pyとurls.pyが変わります。

■app/urls.py

■app/views.py

チョット解説

上に載せた views.pyは一番ゴリゴリやった例です。
例えば11行目~14行目は下のようにFormを使って書くこともできます。

urls.pyからHogeUpdateViewが消えた理由

2つの実装でupdateViewを不要な姿にしています。

  1. POSTの送り先をdetail自身に設定
  2. 関数:HogeDitailViewにて【 if (request.method == ‘POST’): 】とPOSTの値があるときの分岐を用意

こうすることで、POSTの値はdetail自身に渡され、POSTを持つ場合はsave()が走るようになっています。

関数で書いた時に悩むところ

  • NULLを入れたいのにNoneが登録される(場合によってはこれが原因でバリデーションエラーになる)
  • 上書きしたいのに新規追加してしまう

NULL登録の解決策:column01 などにNULLの記載をしたい場合はIfで分岐をする事で対処できます。

新規追加してしまう時に見る場所:pkで抽出したobjectのカラムに対して処理を実行しているか確認しましょう

save()では基本的に INSERT SQL 文が実行されます。save()メソッドは値を返しません。
既にプライマリキーがあるデータの条件を指定した場合は、INSERTでなくUPDATE SQL 文が実行されます。

まとめ

実装していて一番悩んだパートがNullで上書きしたい時の処理でした。

DjangoだとNullではなくてNoneなんだと言う所から躓いたわけですけど、Noneを渡したつもりでいてもエラーが出てきました。 “None”という文字を渡していたとわかった時は思わず苦笑してしまいました。

こういった事って慣れれば大したことじゃないんですけどね。