前回まで で、データベースに入っている文字や数字が、きちっと画面で登録・更新できるのかそれぞれ試した。
今回の、日付でjavascript使うとこと、decimalのリストボックス化は悩んだな。
数字
普通はinteger使う。パーセンテージとかレートみたいなのを扱いたいときは、floatじゃなくdecimalを使う。 floatは誤差が出そうやから使わない。
学術に使うときはfloatのほうがいいのかもしれないけど、お金を扱う場合に誤差が出たら困る。
個数とか通し番号はmodelsの中で「IntegerField」で定義。 重量とかだったら「DecimalField」で定義。
|
|
自分はdjango起点で考えているわけじゃなく、mariadbに業務データがありき、それをdjangoにinspectさせてmodelsを自動生成させたので、型について深く考えて選んだわけじゃない。
むしろmariadbでどう入れるか考えたものをdjangoに解釈してもらった。 データを先に考えて作る。
データベースの型との対照表を書いておられる方がいてわかりやすかった。 mariadbはmysqlのところ参照させてもらった。 作者さんありがとう。
数字の入力項目は、入力フィールドに自動で上下ボタンがつく。

なるほど、マウスだけでカチカチ入力できるってわけか。 「100」って入れたいとき、100回クリックせなあかんのかな。 便利かどうか疑問。

decimalで小数点以下を4桁持たせてると、この矢印ボタンは0.0001単位で値が上下してくれる。
当たり前っちゃ当たり前やけど、こんなん使い物にならへん。
電卓みたいなの表示させて値入力できたらいいのに。 jraで馬券買うときにそんなのが表示されてたっけ。
javascriptで使う部品探したらできるかもしれないけど、今はもうこのままでいい。javascript苦手やし。
文字
普通に扱う。バリデーションで「全角文字だけ」とかできるんかもしれんけど、今はやらん。
|
|
日付
mariadbでdatetimeで作ってある。 create文はこんな感じ。
|
|
日付関連は、実際の登録日とか更新日とかもそのうちつける。 資産関連のテーブルじゃなくて帳簿やったら入金日とか、支払日みたいなのも入れる。
datetimeじゃなくてdateとtimeもあるけど、統一したかったからdatetime。 だから日付しか使わなくてもdatetimeにして時間は「00:00:00」にして扱う。
inspectした結果の日時の入る項目はこう生成されてた。
|
|
djangoでは入力フィールドが「0001-01-01 00:00:00」って形式になる。
日付の取り扱い解説書いておられる型がおられて参考にさせてもらった。 作者さんありがとう。
|
|
mariadbにはタイムゾーンがないらしい。 だから保管日付は、sqlで参照するとJSTで入ったものが表示される。 テストしても「今」の時間が入ってくれるからわかりやすい。
djangoはタイムゾーンがあるらしい。 グローバルなサイトを扱うとき、UTCベースでデータを取り扱いし、表示はJSTにしてくれる。
これを自分のデータベースに照らし合わせると、表示が9時間ズレる!!! なんちゅーことしてくれるねん。
昔見たIISのログの日付みたいなことになってくれる。 これはイカン。 事実が発生した日時がUTCで保存されると、直観的にデータが読めなくなる。
表示のときだけ9時間ズラすことも考えたけど、実際の格納時間は自分にとってJSTで扱う方針は変えられない。
ということで、非推奨と言われるが自分にとってわかりやすさを優先したいため、settings.pyのUSE_TZ記述をfalseに変えた。
|
|
これで時間表示が自分にとって正しくなる。
テンプレートで手動生成する
updateviewで更新画面なんかを表示させるとき、djangoでは少ないコードで一発表示ができる。
|
|
「あー、便利、ありがたい、ありがたい」って思ったのは一瞬。
modelsで書いた項目をテンプレートで表示させられるようになった後、「このまま表示させるわけにはいかない」ってなった。
表示させ方がそのままじゃ気に入らない。というか、使えない。
-
必要のない項目は表示させたくない
-
できるだけリストボックスで選択入力できるようにしたい
-
日付はカレンダー入力させたい
-
URLの入ったテキストボックスの横に「開く」ってボタンをつけて別タブで開くようにしたい
このへんのために、必要な項目だけをmodelsに書いて、テンプレートでは表示項目の画面IDによって、表示展開を手動展開する。
手動展開っていっても、自動展開されたhtmlをマネして好きなように書き直すだけ。
更新画面で文字や数字、リストボックスを扱う
扱うmodelsはGvisZaiko.py。
資産管理するために存在するmariadbのテーブルからinspectdbさせて作ったものに肉付けしてある。
choicesは「値、表示」を列挙して作った。
choicesDBって名前にある箇所は、テーブルのマスタデータから「値、名前」で抜き出してchoicesとして生成させてる。
|
|
マスターテーブルの定義はこんな感じ。「hyojiorder」を好きなように入れておき、とりこむときにソートしたらリストボックスの中での表示位置を好きなようにできる。
|
|
今回表示させた結果はこうなった。わかりにくいけど、最初の3つの項目と「登録日」はupdateviewのためのテンプレート内で値変更できないようにしてる。

次はテンプレート。抜き出すとこんな感じ。 最初に自動生成させたときのhtmlをテキストファイルに残しておいて、特定のidが来たら、そのフィールドごとに展開したい内容を書いていった。 表示のために参考にさせてもらったページもあるけど、基本は自動生成内容をベースに改変して書いた。
「⭐️」のついたあたりを作るとき、それぞれ参考にさせてもらったURLがある。コメントとして入れてある。 それぞれの作者さんありがとう。
|
|
⭐️1 バリデーション用のエラーメッセージ
たとえばデータ全体に関わるようなバリデーションメッセージの表示で{{ form.non_field_errors }}って使うらしい。
1つ1つの項目のバリデーションには、{{ field.errors }}って書いておく。
|
|
意地悪して、更新画面開いているときにmariadbのdockerコンテナ停止したら「保存に失敗しました」とか表示されるのかも。 今度やってみるかな。
⭐️2 inputでは"text"とか"number"と書き、更新できない項目を展開
テーブルの項目は{% if field.id_for_label == "id_serialshubetsu" %}みたいにして頭にid_をつけてひっかけるんだと。
手動展開では、field.xxxを使ってname/id/valueの右辺に書く。
htmlのinputにtypeを書くところがあって、全部"text"って書けばいいと思ってたら、そうじゃない。 試しに、数字が入る項目に"text"って書くとバリデーションにひっかかった。 項目にあわせた属性を書く必要があるらしい。
|
|
最後にreadonlyってつけておくと、画面上で値を変更できなくなる。
これで自動発番した項目とか、データベースでキーにしてる項目とかは更新できなくなってくれる。
⭐️3 日付の書式指定しとく
mariadbではdatetime使ってるので、その書式にあわせるようにする。
settigs.pyに書いてるからか、そのままにしておくと「xxxx年xx月xx日」ってなって、登録するときにバリデーションでひっかかる。
なんやねん、めんどくさいわー。 表示を勝手に変えるんやったら、登録するときも読み替えろやー。
|
|
ひっかからんようにハイフン区切りで年月日を入れておき、時間記録は必要ないなら「00:00:00」って入れておく。 更新画面では登録日を改変させたくないのでreadonlyをつけてる。
「抹消日」って項目は、javascriptでjqueryのdatepickerを使った。いろんなデザインがあるし、パラメータもたくさん。 datepickerはjqueryのサイトで試せるし、「view source」ってサイトにあるからその場でソースも見れてめっちゃ便利。作った人すげー。
画面上ではid_masshoって識別名になっているので、functionの中でひっかけるように書いている。
定義は画面上の項目1つ1つについてひっかける必要があるから、デザインもそれぞれ変えられる。
|
|
表示させるとこんな感じ。おお、かっけー。

もちろんiphoneでも表示できてる。

普段はダークモード使うし、黒い画面に黒いカレンダーになるので、緑の蛍光色っぽいのを選んで月曜日始まりにした。
⭐️4 URL参照させる
djangoにはurlfieldってのがあるらしい。
って、フィールドの型の一覧を書いてくれてた人がいた。 作者さんありがとう。
inspectdbさせたとき、url格納するフィールドはそのままCharFieldって解釈してくれてた。まぁええか。
|
|
このURLの入ったフィールドはリンク切れてないか確認するために、別窓で開いてくれるボタンをつけた。
|
|
見た目はこんな感じ。

⭐️5 そのまま改変させずに表示
テンプレートの中で{{ field.xxx }}って書き方すると展開してくれる。
elseで一番最初に書いた。
特に表示をいじらずdjangoに任せる箇所はこの書き方。
|
|
⭐️6 「戻る」ボタンの設置
最初のclass="darkmode-ignore"は自分用のcssでダークモード使うときのおまじない。もちろんcss定義しとく必要がある。
|
|
「戻る」ボタンを置いておき、javascript使って前の画面に戻らせる。 具体的にはlistviewに戻る。
ボタンとかの挙動を作るときは、javascriptをテンプレートに書いておいて呼び出す。
最初のほうでform method="post" onsubmit="return kakuninPopup()"って書いた箇所から呼ばれる確認ポップアップと、後でURLを「開く」ボタンも置くのでついでに「openURL」も近くに入れておいた。
リストボックス化
リストボックスはdjangoではmodelsの中でタプルを書いておいて、choicesっていう定義に書いて使う。
|
|
値も表示も同じにするだけなら、めっちゃ簡単。ただ、同じにするなんてほぼないはず。

データベースに書き込むときの値と、リストに表示させたい値なんかをいじりたいとき、たとえば自分はdeimalのカラムに入れたいときがあった。
データベースに値をこんな感じで入れておく。

これをマスタデータみたいな感じで使えるようにmodelsを書く。 idはdjangoには必要かもしれんけど、表示には不要なのでmodelsには書かない。
|
|
さらに選択できるように書いておく。c言語のsprintfみたいな書き方できるやん。
|
|
するとこんな感じ。

このdecimalの箇所、最初は手動で書こうとしたら、“0.5000"ってhtmlのoption valueに設定して表示はできるけど、バリデーションで文字列として扱うらしくてデータ保存ができんかった。
実際にテーブルに入れる値と、表示させる値をマスタデータに入れてるの思い出したから、sprintfみたいなやり方探して書いたら"0.5000"って自動展開させても同じように入ってるのに、なぜかバリデーションでエラーにならんかった。
なんでかわからん。ま、リストボックス作れたし今はよしとしましょ。
djangoというかフロントエンドへの思い
確かにdjangoはlistview/createview/updateview/deleteviewを使って楽に書くことができる。 それはそれで素晴らしい。
ただし、それだけでは実際の利用には耐えない。 いつも使いやすい画面ができるわけじゃないから、工夫が必要。
phpで作った機能を移植するため、今は資産管理だけ作ってて、次は帳簿管理も作っていくし、この画面は自分でしか使わないけど、「こう動いてほしい」っていう機能リクエストが実現できるのかっていうのは作り手の努力でなんとかしなきゃいけない。
こういう努力が簡単にできれば、フレームワークやシステムとしてとても優れていると思う。
大昔に自分がまだプログラムを書き始めたとき、N60basicで簡単な演算ができたときは「おー」って驚いた。
めっちゃ合成音やったけど、pc6001mk2が言葉を発したときはビビったし、デモのプログラムでビバルディの「春」が鳴ったときも驚いた。
お金をもらってプログラムを書く喜びを感じ始めたとき、実務でvisual basic2使ってフォーム画面を初めて作ったときも、マウスでボタン押してモーダル画面開けたときは嬉しかった。
やり方忘れたけど、あのときはbtrieveのデータベースも読み込んだっけ。
来年でエンジニア30年目。 djangoのおかげで昔味わった喜びを思い出せた。
この「おー」を味わいたいために、まだまだ書き方探すんやろなぁ。 やめられまへん。