ちょっと必要にかられたのでやってみたら、思ったより手間取ったのでメモしておく。
手間取った理由その1
0.97pre-SVN-6883 だと、django.utils.simplejson でモデルオブジェクトを JSON にできなくなってる。0.96のころはできたように思うんだけど。unicodeブランチのマージの影響か?仕方ないので django.core.serializers でシリアライズしてみたら、JSONとしては使いずらい結果になる。まあシリアライズだから当然か。子要素が展開されずにIDだけというのも困りもの。DTO的に使うのは不向きっぽい。
悩んでてても解決しそうになかったので、HTMLと同じようにJSONもテンプレートでレンダリングすることにした。同じようなことを考える人はいるもので、Django snippets にいいのがあった。
あとはこんなテンプレートを用意してやればいけた。ただし、IE関係は注意が必要。
キャッシュが効いてるみたいなので、パラメータクエリに時刻とかのランダムな値を追加しないとだめっぽい。
閉じ括弧直前の「,」を除いておかないとエラーになる。
文字列はとりあえずダブルクォーテーションで囲む。
boolean は lower フィルタを通しておく。
{
"entities" : [
{% for entry in entities %}
{
"id" : "{{ entity.id }}",
"name" : "{{ entity.name }}"
}{% if not forloop.last %},{% endif %}
{% endfor %}
]
}
手間取った理由その2
pythonとjavascriptで、datetimeのミリ秒以下の扱いが違って困った。あと、ミリ秒まで含む文字列からpythonのdatetimeに変換する方法がわからず、かなり困った。
文字列からpythonのdatetimeへの変換は、文字列から日付型変換と演算 - mitszoの日記を参考にして解決した。ミリ秒まで欲しかったので、ちょっと力技。
from datetime import datetime, timedelta
import time
def str2datetime(datestr):
''' ミリ秒まで含む日時形式の文字列をdatetimeに変換します。
@param datestr yyyymmddHHMMSSsss形式の文字列
'''
base = datetime(*time.strptime(datestr[:-3], '%Y%m%d%H%M%S')[:6])
ms = timedelta(microseconds=int(datestr[-3:]) * 1000)
return base + ms
datetimeを文字列にしたもの->Dateまたは文字列の変換には、dateformat.js - 日付フォーマット変換ライブラリを使った。おかげでかなり楽ができた。JSONにレンダリングするときに、dateフィルタで変換しても良かったかな。
var __dateFormat = new DateFormat("yyyy/MM/dd HH:mm:ss");
var __dateSequential = new DateFormat("yyyyMMddHHmmssSSS");
var __fromPython = new DateFormat("yyyy-MM-dd HH:mm:ss.SSS000");
/*
* python形式の日時文字列(yyyy-MM-dd HH:mm:ss.SSS000)をDateオブジェクトに変換します。
* @param datestr python形式の日時文字列
*/
_pydate2date(datestr) {
if (!datestr) { return ''; }
return __fromPython.parse(datestr);
}
}
/*
* python形式の日時文字列(yyyy-MM-dd HH:mm:ss.SSS000)をyyyy/MM/dd HH:mm:ss形式に変換します。
* @param datestr python形式の日時文字列
*/
_pydate2str(datestr) {
if (!datestr) { return ''; }
return __dateFormat.format(_pydate2date(datestr));
}
/*
* python形式の日時文字列(yyyy-MM-dd HH:mm:ss.SSS000)をyyyyMMddHHmmssSSS形式に変換します。
* @param datestr python形式の日時文字列
*/
_pydate2Sequential(datestr) {
if (!datestr) { return ''; }
return __dateSequential.format(_pydate2date(datestr));