2017-09-04 1 views
0

Je souhaite définir des valeurs de variable, mais uniquement lorsqu'elles ne sont pas déjà affectées et dans un contexte local.Comment puis-je définir une variable (non globale) dans une fonction de contexte jinja?

Donc il y a une solution à ceci:

{% with x=(x | default(1)) %} 
    {{ x }} 
{% endwith %} 

{% with x=2 %} 
    {% with x=(x | default(1)) %} 
     {{ x }} 
    {% endwith %} 
{% endwith %} 

Cela fonctionne bien, mais il est beaucoup de texte. J'ai de nombreuses situations où je n'ai pas un seul mais jusqu'à 20 variables qui sont en train d'être définies et ensuite une macro est appelée, ou un modèle est inclus avec ces valeurs.

Écrire toutes ces conditions par défaut est juste un gâchis et provoque des erreurs. Donc, j'aimerais être en mesure de définir une valeur sur le contexte actuel, par exemple. dans une fonction de contexte. Mais si je les opérations suivantes:

@contextfunction 
def defaults(ctx, **vals): 
    for k,v in vals.iteritems(): 
     if k not in ctx: 
      ctx[k] = v 

Je reçois la une exception:

TypeError: 'Context' object does not support item assignment

Et en essayant de définir une valeur sur ctx.vars ne contribuerait pas non plus:

vars
The template local variables. This list contains environment and context functions from the parent scope as well as local modifications and exported variables from the template. The template will modify this dict during template evaluation but filters and context functions are not allowed to modify it.
http://jinja.pocoo.org/docs/2.9/api/#jinja2.Context.vars

I essayé avec

@contextfunction 
def defaults(ctx, **vals): 
    for k,v in vals.iteritems(): 
     if k not in ctx.vars: 
      ctx.vars[k] = v 

Et il ne donne pas exception, mais semble ne pas attribuer la valeur au contexte. Je sais que je pourrais écrire dans le contexte global mais ce n'est pas ce que je voudrais faire car cela produirait des effets secondaires.

Y a-t-il une possibilité d'obtenir juste le contexte actuel et de lui donner une valeur? Je n'ai trouvé aucune instruction là-dessus et comment cela a pu être fait et je n'ai pas vraiment compris cela en lisant la source jinja.

Répondre

0

J'ai trouvé une solution, en quelque sorte je continue à résoudre mes propres problèmes. Ce n'est pas exactement une réponse à la question de "Comment puis-je définir une variable (non globale) dans une fonction de contexte jinja?", mais il résout le problème.

J'ai écrit une extension de Jinja, qui permet d'un simple tag "par défaut":

from jinja2 import nodes 
from jinja2.ext import Extension 

""" 
    DefaultExtension 
    ~~~~~~~~~~~~~~~~ 
    Very simple jinja extension that allows for the following 

    {% set x=(x | default(1)) %} 
    {% set y=(y | default(2)) %} 

    to be written as 

    {% default x=1, y=2 %} 

    :copyright: (c) 2017 by the Roman Seidl 
    :license: BSD 
""" 

class DefaultExtension(Extension): 
    # a set of names that trigger the extension. 
    tags = set(['default']) 

    def parse(self, parser): 
     #just dump the tag 
     lineno = next(parser.stream).lineno 

     #parse through assignments (similar to parser.parse_with) 
     assignments = [] 
     while parser.stream.current.type != 'block_end': 
      lineno = parser.stream.current.lineno 
      if assignments: 
       parser.stream.expect('comma') 
      target = parser.parse_assign_target() 
      parser.stream.expect('assign') 
      expr = (parser.parse_expression()) 
      #consruct a 'default' filter 
      filter = nodes.Filter(nodes.Name(target.name, 'load'), 'default', [expr], [], None, None, lineno=lineno) 
      #produce an assignment with this filter as value 
      assignment = nodes.Assign(target, filter, lineno=lineno) 
      assignments.append(assignment) 
     return assignments 

Je viens de l'ajouter à mon application:

app.jinja_env.add_extension(DefaultExtension) 

et il fonctionne très bien mais je dois avouer que je ne l'ai pas encore testé très à fond.

Quelqu'un pense que je devrais soumettre cela à Jinja?