Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

TurboGearsのRepeatingFieldSetでinput要素のname属性が変わる

食欲の秋、スポーツの秋、読書の秋、そして、コードリーディングの秋です。いや、もう冬か。

TurboGearsでRepeatingFieldSetとかを使うと、<input>のname属性が勝手に"[RepeatingFieldSet名]-[連番].[input要素名]"に書き変わってるのがきになりました。そこで、ソースを見てみました。

base.py の Widgetクラス

コメントを読む。

class Widget(object):
    """
    A TurboGears Widget.

    '__init__' and 'update_params' are the only methods you might need to
    care extending.
    (.. 略 ..)
    """

    def update_params(self, params):
        """
        This method will have the last chance to update the variables sent to
        the template for the specific request. All parameters listed at class
        attribute 'params' will be available at the 'params' dict this method
        receives.
        (... 略 ...)
        """
        pass

なるほど、update_paramsメソッドをオーバーライドして割り込んで、テンプレートに渡るパラメータを変えられるのか。念のため、displayからこいつが呼ばれてることもチェック。

    def display(self, value=None, **params):
        # ...略...
        self.update_params(params)
        # ...
        output = view.engines.get('kid').transform(params, self.template_c)
        # ...略...

OK、予想通り。

forms.py の InputWidget#update_params

実際にnameを書き換えているのはここ。

d["name"] = build_name_from_path(self.name_path)

build_name_from_path は、forms.pyに関数として定義されてます。



読んでみた感想

初めてまともにPythonのソースを読んでみましたが、他の言語と違って1ファイルにたくさんクラスを詰め込むのに戸惑いました。クラス探すのがめんどいし、1ファイルが長くなります*1

次に、気がついたのはクラスメソッドがないこと。関数がクラスに属している必要がないのでこれを外で直接定義してます。これは、いちいちUtilクラスなんて作るのめんどくさいって考えれば、利点としてあげていいと思います。後、Pythonの場合はファイルをモジュールとして自由にimportできるので、自分で使う目的で定義したただのユーティリティ関数の再利用性も高いなと思いました。

後、継承が有効利用されていて、OOP好きとしてはわくわくする感じのソースです。例えば、RepeatingFieldSet の親クラスの RepeatingFormFieldのソースは以下です。

class RepeatingFormField(RepeatingInputWidget, CompoundFormField):
    pass

さらに、これを継承した RepeatingFieldSetでは、template変数とかフィールド値の設定だけになってます。きれいな継承ツリーを持ってて、DRYを心がけています。美しい限りです。

*1:froms.pyは1282行