FormAlchemy のカスタマイズ¶
FormAlchemy には PostgreSQL の範囲型や配列に対応する renderer が 用意されていない。しかしコードを読んだらカスタマイズはそれほど 難しくはなさそうだったので書いてみた。
要点は、 formalchemy.fields.FieldRenderer をベースにして render(), render_readonly(), deserialize() 等をオーバーライドする。 フォーム出力用に formalchemy.helpers.text_field() というヘルパー函数が 用意されているため、これを利用すれば手間が省ける。 deserialize() はフォームの入力内容をパースする時に呼ばれるメソッドで、 入力内容を解釈して適切な Python オブジェクトに変換する機能を持たせる。
init4range と array 用のコードは以下のようになる。 これを forms.py に追加する。
from formalchemy import FieldSet
from formalchemy.helpers import text_field
from sqlalchemy.dialects.postgresql import INT4RANGE, ARRAY
from formalchemy.fields import FieldRenderer
from psycopg2.extras import NumericRange
class Int4RangeRenderer(FieldRenderer):
def _range_string(self):
# self.value は u"NumericRange(115, 889, '[)')" という文字列になっている
# self.raw_value に NumericRange インスタンスがあるのでそれを利用
# PostgreSQL 内には "[lower, upper+1)" という形式で格納されるようだが
# 解り難いので "[lower, upper]" という形式で入出力する
if isinstance(self.raw_value, NumericRange):
value = "[{},{}]".format(self.raw_value.lower, self.raw_value.upper-1)
else:
value = ""
return value
def render(self, **kwargs):
return text_field(self.name, value=self._range_string(), **kwargs)
def render_readonly(self, **kwargs):
return self._range_string()
FieldSet.default_renderers[INT4RANGE] = Int4RangeRenderer
class ArrayRenderer(FieldRenderer):
def render(self, **kwargs):
value = " ".join(self.raw_value)
return text_field(self.name, value=value, **kwargs)
def deserialize(self):
# スペース区切りの文字列として受け取る
data = self.params.getone(self.name)
data = data.split()
return data
FieldSet.default_renderers[ARRAY] = ArrayRenderer
FormAlchemy の設計では配列型の中身のデータ型に応じて default_renderer を切り替えるようにはできないので、上記コードでは 配列型を一緒くたに扱っている。
前の投稿:
Pyraid + GeoAlchemy2 + GeoFormAlchemy2 (4)
次の投稿:
FileReader.readAsBinaryString は Binary を返さない