CakePHP使いがDjangoでサイトを作ってみた 〜一度だけ表示したいメッセージ〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
最後まで記事を読んで……ください

この記事を三行にまとめると

本当に大事なことは何度も言った方が良いと思います
本当に大事なことは何度も言った方が良いと思います
大事なことなので二回言いました
ウェブサイトでよくデータの登録などが行われた後に、リダイレクト先で「データを登録しました」みたいなメッセージが出ることがあります。あれは登録直後に一度だけ表示されるもので、リロードしてページを読み込み直した時は出ないようになっています。

CakePHPだとFlashコンポーネントを使えば簡単に実装できるんですけど、Djangoにも似たような機能はあるので今日はそれを使ってみたいと思います。



view.py

まずはビュー側でメッセージをセットする方から。

#モジュールの読み込み
from django.contrib import messages

class index(TemplateView) :
  def get(self, request) :
    #メッセージをセット
    messages.add_message(request, messages.INFO, 'Hello world.')
    redirect('index')

簡単に書くとこんな感じです。必要なモジュールを読み込んで「add_message」関数を使うだけ。2番目の引数にはメッセージのレベルを、3番目の引数にはメッセージの内容を入れます。

メッセージのレベルってのはinfoとかwarningとかerrorとか、そのメッセージがどんな類のものかを示すものです。とは言ってもエラーに関するメッセージはレベルをerrorにしとかないと動かないとかそういうことではないので、自分で「このメッセージはエラーに関するものとします」みたいな決め事に使えるって感じです。



template

続いてビューでセットしたメッセージをテンプレートで出力する方法です。

{% if messages %}
  {% for message in messages %}
    <div class="{{message.tags}}">{{message}}</div>
  {% endfor %}
{% endif %}

これでオッケーです。メッセージ自体は配列だかオブジェクトだかで入っているようなので、for文を使って表示する必要があります。「{{message.tags}}」には先ほど設定したエラーレベルに応じた文字列が入っています。上記の例では「messages.INFO」を使用したので、{{message.tags}}の中には「info」が入っています。

つまり実際に画面に出力される内容はこんな感じになるってことですね。

<div class="info">Hello world.</div>

なのでcssでerrorとかwarningクラスにスタイルを当てておけばエラーレベルに応じたデザインのメッセージを表示できます。



それから先ほどメッセージは配列で入ると言いましたが、add_messege関数を複数回呼び出した場合は内容が上書きされるわけではなく新たに追加されていくので、例えば二回連続で呼び出すとこうなります。

#view.py
from django.contrib import messages

class index(TemplateView) :
  def get(self, request) :
    messages.add_message(request, messages.INFO, 'Hello world.')
    messages.add_message(request, messages.ERROR, 'There is an emergency.')
    redirect('index')

#index.html
{% if messages %}
  {% for message in messages %}
    <div class="{{message.tags}}">{{message}}</div>
  {% endfor %}
{% endif %}

#画面の出力
<div class="info">Hello world.</div>
<div class="error">There is an emergency.</div>



ショートカット関数

add_message関数を使う場合はエラーレベルを引数で設定しないといけませんが、messagesモジュールにはそれぞれのエラーレベルでメッセージをセットできるショートカット用の関数があるそうなので、それ使えばちょいコードがシンプルになります。

messages.debug(request, 'デバッグ')
messages.info(request, 'インフォ')
messages.success(request, 'サクセス')
messages.warning(request, 'ワーニング')
messages.error(request, 'エラー')

テンプレート側で出力する方法は同じです。






最近はSPAとかいう週刊誌だか売買契約書だか知りませんが、フロント側は全てjavascriptで制御するやり方が増えていると思うので、メッセージの表示などもそっちでやっちゃうことが多いような気もするんですが、こういう一度だけメッセージが出てほしい機能は今でもよく使われそうだから、たいていのフレームワークには実装されているのかもしれないですね。特にショートカット関数の書き方なんてCakePHPとほとんど一緒ですしね。

//CakePHP3の場合
$this->Flash->info('いんふぉ');
$this->Flash->success('さくせす');
$this->Flash->warning('わーにんぐ');
$this->Flash->error('えらー');

何かスタンダードな仕様があるのかもしれません。

そういや学生時代に先生が「大事なことだから一度しか言わないぞ」って言うことがありましたけど、実際のところ、本当に大事なことは何度も言った方が良いと思います。たぶん先生は大事なことだから絶対に聞き逃すなよという警告の意味で一度しか言わないって言ってたんだと思いますけど……ちゃんと聞いてたつもりでも聞き逃した部分とか、全部聞き取れたけど一度では理解できなかったことって、社会人になってからもわりとあるような気がしますしね。伝え方が悪くて伝わらないことだってよくあるし。でもそれで聞き返した時にもしも「二度は言わねえよ。あとは自分で考えろ」って言われちゃったら、正直な話どうしようもないですよね。一度で理解できなかったこっちに非があるのかもしれないけれど、例えばそれをもう一度ちゃんと聞いて理解しないと作業が先に進まないみたいな時にもう言わねえとか言われても、こっちとしても「じゃあ作業はできねっす」って開き直るしかなくなっちゃうもんな……。

だからやっぱり、本当に大事なことは何度も言った方が良いと思います(大事なことなので二回言いました)
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください