2011-06-21 4 views
2

渡されるオブジェクトのタイプに応じて異なる実装を呼び出すJinjaマクロを持つ方法を探しています。基本的に、標準のPythonメソッドの多型。今、私はこれに似た醜い回避策を使用しています:純粋なPythonでJinjaの多態マクロ

{% macro menuitem(obj) %} 
    {% set type = obj.__class__.__name__ %} 
    {% if type == "ImageMenuItem" %} 
    {{ imagemenuitem(obj) }} 
    {% elif type == "FoobarMenuItem" %} 
    {{ foobarmenuitem(obj) }} 
    {% else %} 
    {{ textmenuitem(obj) }} 
    {% endif %} 
{% endmacro %} 

を、1は、例えば、モジュールの環境と周りにマックすることができますglobals()[x+'menuitem']ですが、これはきれいではありませんが、非常にうまく動作します。私はJinjaの文脈を使って同様のことを試みましたが、後者はマクロ定義を含んでいないようです。

私が求めているものを達成するためのより良い方法はありますか?

答えて

2

時間は、)HTMLを含んでいます、私はpresentメソッドで直接HTMLマークアップで混乱したくありません。そこで私はPythonでメニュー定義を実装しました。これはJinjaのプレゼンテーションで、ギャップを橋渡しする相互再帰があります。メニュー項目の

異なるタイプは、異なるサブクラスで表される:上記参照

class MenuItem(object): 
    def present(self, macromap): 
     return macromap[type(self).__name__](self, macromap) 

class TextLink(MenuItem): 
    def __init__(self, url, text): 
     self.url, self.text = url, text 

class Section(MenuItem): 
    def __init__(self, text, items): 
     self.text, self.items = text, items 

class ImageLink(MenuItem): 
    ... 

macromapはrepresenationを実装マクロにメニュー項目のタイプをマッピングする辞書です。これは、すべての神社で定義されています:

{% macro TextLink(l, macromap) %} 
    <a class="menuitem" href="{{l.url|escape}}"> 
    {{ l.text|escape }} 
    </a> 
{% endmacro %} 

{% macro Section(s, macromap) %} 
    <div class="heading">{{s.text}}</div> 
    <ul class="items"> 
    {% for item in s.items %} 
     <li>{{ item.present(macromap) }}</li> 
    {% endfor %} 
    </ul> 
{% endmacro %} 

{% set default_map = {'TextLink': TextLink, 'Section': Section, ...} 

実際のメニュー定義がきれいMenuItemサブクラスの木のように表現されていますプレゼンテーションをキックオフするには

main_menu = section("Main Menu", [ 
    section("Product Line 1", [ 
     TextLink("/products/...", "A product"), 
     ... 
    ]), 
    section(...), 
]) 

、テンプレートはトップレベルのセクションのを呼び出す必要がありますpresentメソッドで、メニューを表示する方法を指定するマクロマップを渡します。 main_menu.present(default_map)Sectionマクロで最もよく分かるように、メニュー項目は、子どもたちに自分自身を提示するよう依頼することができ、presentメソッドは別のJinjaマクロを呼び出すなど、再帰的に呼び出すことができます。

マクロマップを明示的に渡すことはあまり美しいものではありませんが、メニューの定義に全く触れることなくメニューデータの表現を簡単に変えることができます。例えば、メインのウェブサイトメニューをレンダリングするためにマクロマップを定義したり、モバイルデバイス用のバリアント(CSSが不十分な場合)やXMLサイトマップ、またはプレーンテキストバージョンをレンダリングすることができます。 (実際には、このシステムをウェブサイトのメニューやサイトマップのケースに使用してしまいました)

7

OOPの本質:多型。

Create a presentation Layer for your objects: 

class MenuPresentation: 
    def present(self): 
     raise NotImplementedException() 

class ImageMenuPresentation(MenuPresentation): 
    def present(self): 
     return "magic url " 

class TextMenuPresentation(MenuPresentation): 
    def present(self): 
     return "- text value here" 

そしてだけの問題になります:メニュー項目のプレゼンテーション以来できる(との最も:私は今、1つの顕著な違いは、fabrizioMが提案する方法と同様に私の問題を解決した

{% macro menuitem(obj) %} 
    {{ obj.present() }} 
{% endmacro %} 
+0

多態性は実際にこの問題に役立ちます。しかし、プレゼンテーションにはHTMLが含まれていなければなりません。これは本当にJinjaテンプレートに分けておきたいものです。あなたの提案は、私が問題を解決するために必要な最後の手がかりを提供しました。 –