2014-04-19 6 views
5

Czy można napisać rozszerzenie Jinja2, które podczas renderowania ma dostęp do kontekstu szablonu? Chcę napisać rozszerzenie, które uzyskuje dostęp do zmiennej kontekstowej i generuje pewne dane na podstawie tej zmiennej. Nie mogłem znaleźć wystarczających informacji, jak napisać takie rozszerzenie.Rozszerzenie Jinja, które ma dostęp do kontekstu

Teraz mam to:

class CsrfExtension(jinja2.ext.Extension): 
    r""" Adds a {% csrf %} tag to Jinja. """ 

    tags = set(['csrf']) 
    template = '<input type="hidden" name="csrfmiddlewaretoken" value="%s">' 

    def parse(self, parser): 
     token = next(parser.stream) 
     lineno = token.lineno 
     return self.call_method('_render_csrf', lineno=lineno) 

    def _render_csrf(self, value, name, *args, **kwargs): 
     csrf_token = somehow_get_variable('csrf_token') 
     return jinja2.Markup(self.template % csrf_token) 

Ale w foo.jinja

<!DOCTYPE html> 
<html> 
    <body> 
     <h1>This is a Test</h1> 
     {% csrf %} 
    </body> 
</html> 

dostaję

SyntaxError at/
invalid syntax (foo.jinja, line 7) 

myślałem, że dostać NameError od somehow_get_variable() nie jest określone. Muszę wiedzieć: a) jak uzyskać zmienną z bieżącego kontekstu, oraz b) jak poprawnie napisać rozszerzenie.

Ponadto, dlaczego linia 7? Znacznik {% csrf %} znajduje się na linii 5. Nawet gdy przycinam foo.jinja, aby zawierał tylko jedną linię ze znacznikiem {% csrf %}, będzie to oznaczać wiersz 7.

Odpowiedz

7

Znaleziono. Wygląda na to, że Jinja generuje kod Pythona z AST AST (?) I ta konwersja się nie powiodła, dlatego spowodował błąd SyntaxError. jinja2.nodes.ContextReference() może być użyty do uzyskania kontekstu renderowania.

class CsrfExtension(jinja2.ext.Extension): 
    r""" Adds a {% csrf %} tag to Jinja. """ 

    tags = set(['csrf', 'csrf_token']) 
    template = u'<input type="hidden" name="csrfmiddlewaretoken" value="%s">' 

    def parse(self, parser): 
     lineno = next(parser.stream).lineno 
     ctx_ref = jinja2.nodes.ContextReference() 
     node = self.call_method('_render_csrf', [ctx_ref], lineno=lineno) 
     return jinja2.nodes.CallBlock(node, [], [], [], lineno=lineno) 

    def _render_csrf(self, context, caller): 
     csrf_token = context['csrf_token'] 
     return jinja2.Markup(self.template % unicode(csrf_token)) 

csrf = CsrfExtension