2011-06-21 45 views
2

我正在尋找一種方法來讓Jinja宏調用不同的實現,具體取決於正在傳遞的對象的類型。基本上,標準的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 %} 

在純Python,一個可以圍繞淤泥與模塊的環境中,例如globals()[x+'menuitem'],這並不漂亮,但效果很好。我嘗試過使用Jinja上下文類似的東西,但後者似乎沒有包含宏定義。

有什麼更好的方法來實現我正在尋找的?

回答

2

現在我已經解決了我的問題類似fabrizioM如何建議,但有一個明顯的區別:由於菜單項演示可以(而且大部分時間,)包含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" 

然後會像下面這樣:

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

多態性確實適用於這個問題。但是,演示文稿必須包含HTML,我真的很想將它們分離出來放入Jinja模板中。您的建議提供瞭解決問題所需的最終線索,但非常感謝! –