2011年4月28日木曜日

Action、RenderAction、Partial、RenderPartialの違い

Action、RenderAction、Partial、RenderPartialの違いをよく忘れるので覚書。

まずActionとPartialの違い
Action は MVC のサイクルそのまま。つまり Controller の作成し Action を呼び出し、View の返却という流れ。Partial は View を返却するだけ。

ActionとRenderActionの違い
Action は 結果を文字列として返却するだけ。RenderAction は結果を Response にそのまま書き込んでくれる。それなので大量の Html を出力する場合などは RenderAction を使用するほうが効率的になる。

PartialとRenderPartialの違い
Partial は MvcHtmlString を返却するだけ。RenderPartial は呼び出し元の View にそのまま書き込んでくれる。それなので生成された Html をいじりたい場合などは Partial を使用する。言わずもがなパフォーマンス的には RenderPartial の方が良い。

2011年4月25日月曜日

複数選択を行える便利なjQueryのリストプラグイン その2

以前「複数選択を行える便利なjQueryのリストプラグイン ~ multiselect」という題で複数選択を行えるjQueryのプラグインを解説したけれど、先日これを使う機会がまたあり、触ってみたらEncoding周りで苦労したので解説しておく。


前回解説したときは英語を使用していたので気付かなかったのだが、日本語で使用するとプラグインそのままだと不便な箇所がいくつかあったのでそれの修正点もあわせて解説していく。ちなみに今回の環境はGoogle App Engine PythonをサーバとしフレームワークにはDjango-nonrelを使用している。

まずこちらのgithubからソースコードをダウンロードしよう。git cloneでダウンロードするとajax対応ではないソースコードが落ちてくるので画面右上のDownloadボタンから取得するように。ZIPファイルを解凍すると色々とファイルが入っているけれど、今回は下図のようなフォルダ構造にした。


実際のHtmlとプラグインを使用するJavascriptコードは下記のようになる。
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.12/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/multiselect/plugins/localisation/jquery.localisation-min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/multiselect/plugins/tmpl/jquery.tmpl.1.1.1.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/multiselect/plugins/blockUI/jquery.blockUI.js"></script>
<script src="{{ STATIC_URL }}js/multiselect/ui.multiselect.js" type="text/javascript"></script>

<script type="text/javascript">
 $(function(){
  $.localise('ui.multiselect', {language: 'ja', path: '{{ STATIC_URL }}js/multiselect/locale/'});
  $("#groups").multiselect({
   remoteUrl: "/community_web/group/search"
  });
 });
</script> 

<select id="groups" class="multiselect" multiple="multiple" name="groups">
</select>

{{ STATIC_URL }}という記述はDjangoのテンプレート機能なので他のフレームワークを使用している場合は適切な形に修正して欲しい。前回解説したときと比べて変わったのはlocalizationプラグインを使用してローカライズを行っている箇所だ。下記にui.multiselect-ja.jsの内容を示す。

$.extend($.ui.multiselect.locale, {
 addAll:'すべて追加',
 removeAll:'すべて削除',
 itemsCount:'#{count}個選択',
 itemsTotal:'#{count}個',
 busy:'処理中...',
 errorDataFormat:"データ形式が予期しない形です。処理を続行できません",
 errorInsertNode:"選択肢を追加するときに問題が発生しました:\n\n\t[#{key}] => #{value}\n\n処理は中止されました。",
 errorReadonly:"選択肢 #{option}は読み取り専用です",
 errorRequest:"データ取得中にエラーが発生しました。 (Type: #{status})"
});

これで上記の内容で日本語表示される。ついでui.multiselect.jsのほうに手を加える。

// _registerSearchEvents内の$.ajaxを下記のように修正する
$.ajax({
 url: that.options.remoteUrl,
 data: $.extend(params, {q:encodeURIComponent(value)}),  // ここ重要
 success: function(data) { 
  that.addOptions(data);
  that._setBusy(false); 
},

デフォルトではサーバに投げるクエリ文字列をescape()でエンコーディングしているけれど、escapeが出力するエンコーディングはW3C標準ではないので、Django側で受けたときに正しくデコードできない。そのためescapeに変わってencodeURIComponent()を使用する。

それに併せて使い勝手の上でmultiselectのそのままの仕様だと日本語入力しづらいことこの上ないので、下記のように入力にあわせた自動検索を無効化しておく。

switch (e.which) {
 case 13:   // enter
  _searchNow(true);
  return false;

 //default:  // これをコメントアウト
 // timer = setTimeout(function() { _searchNow(); }, Math.max(that.options.searchDelay,1));
}

上記に併せてsearchDelayオプションも不要になったので気になる人は削除しておこう。これでクライアント側の準備は整ったのでサーバ側を見てみよう。リクエストハンドラーとして下記の一文をurlpatternsに追加しておく。

//...省略
(r'^community_web/group/search', 'community_web.views.group.search'),
//...省略

実際のリクエストハンドラーは下記。
group.py
def search(request):
    query = request.GET.get('q', None)    
    if query:
        query = urllib2.unquote(query.encode('ascii')).decode('utf8')
        list = ['%s=%s' % (group.id, group.title) for group in Group.objects.filter(title__startswith=query)]
        results = '\n'.join(list)
    else:
        results = ''        
    return HttpResponse(results)

検索文字列を取得するところでごにゃごにゃとやっている解説は下記の通り。
まず、query.encode('ascii')でobjectから文字列に変換している。ついで、urllib2.unquote()でエスケープ文字を普通の文字に変換している。そして最後にUTF8でデコードして完了。

これで日本語でも複数選択のプラグインが正常に動作するはずだ。

2011年4月4日月曜日

Google App Engine 開発サーバをコマンドラインから起動する

Windows 7 上で Google App Engine の Python をいじり始めたので今後のための備忘録とか、いまさらの内容とか。

手始めに Getting Started をざっと読んでみて、実際にちょこちょこいじり始めたら、しょっぱなの開発サーバをコマンドラインから起動するところではまったので今回はそれを。ランチャーを使えばこんなところ問題ないんだろうけど、やっぱりこういうのを見せられるとコマンドをぺこぺこ打つのをまねしたくなっちゃうわけで。

Hello, world! の Testing the Application の項でコマンドラインからの起動は helloworld フォルダで下記のコマンドを入力してね、となっているけれど動かない。

google_appengine/dev_appserver.py helloworld/

まず dev_appserver.py 自体が認識されない。GAE Python SDK をインストールするときに環境変数の Path へ下記の値が追加されているのだけれど、それが認識されない。

C:\Program Files\Google\google_appengine

※環境変数の確認方法
コンピュータ→プロパティ→システムの詳細設定→環境変数

よくよく見ると Path が追加されているのはユーザー環境変数のほう。それなのでシステムの環境変数の Path へ先ほどのパスを追加する(;で他のパスと区切るのを忘れないように)。これでコマンドラインで dev_appserver.py と入力すると GAE の開発サーバ用スクリプトが認識されているはずだ。

ついでアプリケーションのフォルダへ移動するのだが、そのまま helloworld に行くと都合が悪い。実際には helloworld の親フォルダへ移動する。helloworld フォルダが下記パスだとする。

c:\gae\helloworld

上記の場合は下記フォルダへ移動する。

c:\gae

この状態で下記コマンドを実行すると開発サーバが正常に起動される。

dev_appserver.py helloworld/

と、まぁ大した内容ではないのだけれど、ドキュメントのままだと動かんね、ということで。