2012年1月19日木曜日

python MySQLdb で取得したデータを Jinja2でrenderすると UnicodeDecodeError

MySQLから取得したデータをJinja2を使って出力する場合、
MySQLdbモジュールのconnect関数でConnectionオブジェクトを取得する際に、
use_unicodeとcharset引数を設定し、取得結果の文字列をunicodeで保持する必要があります。

API - Jinja2 2.7-dev documentation Unicode
http://jinja.pocoo.org/docs/api/#unicode

下記の記述があります。
Jinja2 is using Unicode internally which means that you have to pass Unicode objects to the render function or bytestrings that only consist of ASCII characters.
訳:
Jinja2 の内部処理はUnicodeを使用しているので、render関数にはUnicodeオブジェクトかASCII文字のみからなるバイト文字列を渡す必要があります。

MySQLdb User's Guide MySQLdb Functions and attributes
http://mysql-python.sourceforge.net/MySQLdb.html#functions-and-attributes
connect(parameters...)
use_unicode
charset

以下に実例を示します。

$ python
Python 2.7.1 (r271:86832, Nov 10 2011, 09:26:52) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb as db
>>> import jinja2 as j2
>>> def get_rows_with(con):
...     with con:
...         cur = con.cursor()
...         cur.execute("select * from test_table")
...         rows = cur.fetchall()
...         cur.close()
...     return rows
... 
>>> t = j2.Template('{% for row in rows %}{{ row[0] }} | {{ row[1] }}\n{% endfor %}')
>>> con = db.connect(host='localhost', db='test', user='test_user', passwd='xxxx')
>>> rows = get_rows_with(con)
>>> print t.render(rows=rows)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.7/site-packages/Jinja2-2.6-py2.7.egg/jinja2/environment.py", line 894, in render
    return self.environment.handle_exception(exc_info, True)
  File "