jQueryからPOSTした値を連想配列にする@python

ブラウザからサーバーに連想配列のような値を渡したいときがあります。
phpではinputタグの中の値を


name="abc[a][b][c] value="some_value"
とすれば、フォームを送信すると、自動的に連想配列としてアクセスできます。
が、pythonではキーが"abc[a][b][c]"というような文字列になってしまい、
連想配列として扱えませんでした。
abc.a.b.cになっていれば分解してくれるモジュールがあったと思いますが、
jQueryのPOSTは角括弧の方になっているので、
リクエストのキーを連想配列に分解する関数を自分で書きました。
ただし、全く同じキーがあるときは後で読まれた値しか入らないようになっているので、
使うときはその辺りにご注意ください。

#sample data
params = {
  "abc[a][b][c]": "@m1m0r1",
  "abc[a][b][d]": "@shinout",
  "abc[a][c]": "@gemmbu",
}

requestToDict(params)

のようにして使います。

以下コードです。

def requestToDict(params):
  def buildDict(d, keylist, value):
    if not keylist:
      return value
    key = keylist[0]
    if key not in d:
      d[key] = buildDict(dict(), keylist[1:], value)
    else:
      buildDict(d[key], keylist[1:], value)
    return d

  def setval(d, key, value):
    keylist = key.replace("]", "").split("[") #keylistを作る
    buildDict(d, keylist, value)

  dic = {}
  for key, val in params.iteritems():
    setval(dic, key, val)

  return dic

Kay FrameworkのFormフィールドに初期値を入れる

@m1m0r1です。
Kay Framework dev lounge #4に行ってきました。
Kay作者の松尾さんにも色々質問できて楽しい時間でした。次回もぜひ行きたいです。

Kayフレームワークのフォームを使おうとして分からなかったところが一つ解決しました。
フォームフィールドにデフォルト値を入れる方法です。

form = forms.ContactForm(initial={"subject":u"Decks開発日記。"})

のように、initialにフォーム名と値の辞書を渡せばOKでした。
Formの基本的な使い方やContactFormクラスの定義は、
ドキュメントhttp://kay-docs-jp.shehas.net/forms-usage.htmlを参照してください。

テンプレートの方でcall機能を使うと、renderを呼ぶときに自由にアトリビュートを付けることもできます。
最初はこれでvalueをつけようとしたのですが、二重定義でエラーになってしまっていました。
しかし試しにvalue_としてみたら、ここでvalueを入れることもできました。

{% call form() %}
{{ form['subject'].render(myattr="somevalue", value_=u"Decks開発日記", class_="myLabel")|safe }} 
{% endcall %}

pythonの連想配列シリアライズの速度比較 (simplejson vs pickle)

python連想配列をDBに入れるときにシリアライズする方法を調べてみました。
最初はdjangoのsimplejsonを使うことを考えていましたが、
標準でpickleというモジュールがあることを知ったので速度比較してみました。
結果から見るとsimplejsonの方がシリアライズはわずかに速く、戻すのは2倍ぐらいかかりました。


encode json:
user 0m3.316s
decode json:
user 0m7.883s
encode pickle:
user 0m3.701s
decode pickle:
user 0m3.407s

ネストを含む連想配列dについて10000回ループしました。
使ったデータがマル秘だったのでソースコードは一部だけ載せておきます。

from django.utils import simplejson
import pickle

d = {
  #略
}
j = simplejson.dumps(d)
p = pickle.dumps(d)

#以下の部分だけ4通り変えて計測
simplejson.dumps(j)  #json encode
simplejson.loads(d)   #json decode
pickle.dumps(p)  #pickle encode
pickle.loads(d)  #pickle decode

HTML5のsessionStorage、文字列に型変換されるから注意。

HTML5の新しい変数sessionStorageを使ってみました。
僕の勘だとこいつは以下のようなユースケースに最適。


「詳細設定」ボタンなんかを作りました。
これを押すと詳細設定のブロックが表示されます。
再度押すと非表示になります。
リロードすると、非表示になっちゃうけど、
それは避けたい。
いったん表示にしたら表示のままでいてほしい!

こんな感じ。
このときには以下のコードになります。

<p><span id="settingButton">詳細設定</span></p>
<div id="setting">
<dl>
<dt>設定1<dt>
<dd><input type="text" name="setting1" /></dd>
</dl>
</div>
// jQueryしか書けない体になってしまった元mootools使い@shinoutです。
$(function(){
  sessionStorage["setting"] = sessionStorage["setting"] || false; // 最初は非表示
  
  // 現在のsessionStorage["setting"]を表示に反映させる
  $("#setting")[ sessionStorage["setting"] ? "show" : "hide"]();

  // クリックで toggle
  $("#settingButton").click(function(){
    sessionStorage["setting"] = ! sessionStorage["setting"];
    $("#setting")[ sessionStorage["setting"] ? "slideUp" : "slideDown"]();
  });
});


ロジックとして何をやってるかというと、
sessionStorage["setting"]の値に合わせて、表示、非表示をさせているという話。
読み込み時に参照し、
クリック時に設定&参照することによって表示と連動させられます!


一見よさそうに見えるコードですがこれ、正常に動作しません。

実は、[Storageのデータはすべて文字列で入る]ということを考えてませんでした。


だから、sessionStorage["setting"]は,"false"という名の文字列になってしまっています。

で、いろいろ試してみたんですが、

Boolean("false"); // 型のキャスト!これ boolean (true) ですから。残念。

だから結局、
sessionStorage["setting"]に何らかのフラグ文字を入れるという解決になりました。

$(function(){
  sessionStorage["setting"] = sessionStorage["setting"] || "HIDE"; // 最初は非表示
  
  // 現在のsessionStorage["setting"]を表示に反映させる
  $("#setting")[ sessionStorage["setting"]=="SHOW" ? "show" : "hide" ]();

  // クリックで toggle
  $("#settingButton").click(function(){
    sessionStorage["setting"] = sessionStorage["setting"] == "SHOW" ? "HIDE" : "SHOW";
    $("#setting")[ sessionStorage["setting"]=="SHOW" ? "slideUp" : "slideDown"]();
  });
});


こんなかんじで。

なおlocalStorageも同様に文字列として保存しますので注意。

Google App Engineでエンティティのidを自前で振る

Google App Engineのエンティティはput()でセーブしたタイミングでidが振られます。

from google.appengine.ext import db

#モデル定義
class SomeModel(db.Model): pass

sm = SomeModel()
sm.put() #ここでsm.key().id()が振られる

keyの名前をユニコード文字列で振ることもできるようです。

sm1 = SomeModel(key_name="something")
sm1.put() #ここでsm1.key().name()が振られる

とします。このときはidは振られません。

idを決めて登録するには先にkeyを作ってしまえばOKでした。

id = 10L
key2 = db.Key().from_path(SomeModel.kind(), id)

sm2 = SomeModel(key=key2)
sm2.put()

ただし、自前でidを振ってしまうと、ストアに入っているkeyと重複する恐れがあるので、
テストやデータリストア以外ではやらない方がいいと思います。

phpのマジックメソッド、__set()の挙動

<?php
class Sample{
     public function __set($name, $value){
         $this->$name = "Setted".$value;
     }
}
?>

こんなクラスがあったとして、
これを以下のようにするとどうなるでしょうか。

<?php
$sample = new Sample;
$sample->abc = "VALUE";
echo $sample->abc;  // SettedVALUE だろうよ。
echo "<br />";

$sample->abc = "2ndVALUE";
echo $sample->abc; // さて、ここが問題。
?>

問題の箇所はどう表示されるのかっていうと、

× Setted2ndVALUE
○  2ndVALUE

これはつまり、

__set() メソッドは、
一度セットされたプロパティへの再度の代入の際には呼び出されないってことですね。

では

<?php
$sample = new Sample;
$sample->abc = "VALUE";
unset($sample->abc);  // 消した!
$sample->abc = "2ndVALUE";
echo $sample->abc; // ここはどうなんだ?

予想通りこれは、

Setted2ndVALUE

と表示されました。

要するに__set()メソッドは、
isset と同じ条件で呼び出されるってこと!

【bash】aliasの設定を簡単でたのしく。

$HOME/.custom.profile というファイルを作って、

# 思いついたときにエイリアスをかけるライフハック。
alias setting="vim $HOME/.custom.profile"
alias reflect="source $HOME/.custom.profile"

# こっからはサンプル。気にしないでスルーしてくれてOK
export YOURNAME_DIRNAME=$HOME/where/you/go/frequently
function goto { say $1;pushd $1;ls; }
function back { say "get back to where you once belonged";popd;ls; }
alias gotodir="pushd $YOURENAME_DIRNAME;ls"
alias back="popd;ls"

alias asdf="clear"

alias gist="git status"
alias gita="git add -A"
alias gib="git branch"
alias gim="git commit -m"

alias my="mysql -uyour_beautiful_name -pForSecurityYouShouldNOTWriteThePasswordHere"

alias apconf="sudo vim /etc/apache2/users/your_beautiful_name.conf"
alias aprestart="sudo apachectl restart"
alias hosts="sudo vim/etc/hosts" 

# and so on ...

この設定をいつも読み込ませるように、
$HOME/.bash_profile に

source $HOME/.custom.profile

を追加しておきます。

こうすると

setting
とすればこのファイルが編集できて、
reflect
で反映できます。

ユースケース


1. あれ、このコマンドいつも使うなあ。
2. setting
3. aliasとかfunctionとか書く。(満足しなきゃscript書いてもいいけど)
4. reflect で即時反映。
5. 快適コマンドライフを楽しむ。

注意してほしいのは、

export PATH=/some/new/path:$PATH

など、追加系命令をこのカスタムプロフィールに書いてしまうと、
reflectするときにPATHがものすごいことになるぞと。

こういうのは.bash_profileに書けばいいわけです。