A way to set default values in templates #703

Open
emehrkay opened this Issue Mar 29, 2013 · 6 comments

Comments

Projects
None yet
4 participants
Contributor

emehrkay commented Mar 29, 2013

I've been trying to get some method to set a default value without any real success. In Jinja you can do:

{% set name=name or "John Doe" %}

But that doesn't work with Tornado because name isn't defined and I can't quite figure out what in web.template to modify to get it to work.

This would be useful for situations like:

{% set input_type=input_type or "text" %}
{% set value=value or "" %}
{% set attrs=attrs or "" %}
<input type="{{ input_type }}" value = "{{ value }}" {{ attrs }} />

Am I missing something obvious? Thanks

Contributor

ajdavis commented Mar 29, 2013

Does RequestHandler.get_template_namespace suit your need?

Contributor

emehrkay commented Mar 29, 2013

I don't think so as I want to define defaults in the template html itself. But maybe you can explain how that method helps

Funny thing: I believe that get_template_namespace (and others) were added because I asked if it were possible to parse string as a template a few months ago.

Contributor

ajdavis commented Mar 29, 2013

Well, you could define some defaults in get_template_namespace:

class MyHandler(tornado.web.RequestHandler):
    def get_template_namespace(self):
        ns = super(MyHandler, self).get_template_namespace()
        ns.update({
            'name': 'John Doe',
        })

        return ns

If you wanted that default available to many handlers, you could define get_template_namespace in a base class.

But you said you want to do it in the template itself. You could do:

{% set myname = globals().get('name', 'John Doe') %}
{{ myname }}

Or, less hackily:

{% try %}
    {% set myname = name %}
{% except NameError %}
    {% set myname = 'John Doe' %}
{% end %}

{{ myname }}
Contributor

emehrkay commented Mar 29, 2013

Thanks, these both work.

I previously tried the try/except with no luck, but that was in a 2.3 install, I may have been catching the wrong exception. I do prefer the dict.get approach because that is what I use to get arguments in the controller methods and it just looks better.

This should be in the documentation because it is very useful.

Thanks again

Owner

bdarnell commented Mar 30, 2013

The problem here is that technically the variables passed into the render() method are "globals", while the template itself is a function with its own "local" namespace. This results in UnboundLocalErrors just like you'd see in Python code that tried to overwrite a global variable from a function. You can either use Jesse's suggestion with globals().get() or just use a different name for the local variable:

{% set myname = name or 'Default' %}
{{ myname }}

Tornado's templates are flexible enough that this will kind of work:

{% set global name %}
{% set name = name = 'Default' %}
{{ name}}

but it's a bad idea both because it's kind of an abuse of the "set" statement and because it modifies a dictionary other than the template rendering namespace. I think this turns out to be safe in the current implementation, but I wouldn't want to count on it.

Ideally the parameters passed in to the templates would count as "local" and everything would work the way you originally expected. I think I tried this once and ran into some weird issue, but if someone feels up to making another attempt at it I'd be interested in seeing the results.

bdarnell added the template label Jul 16, 2014

@Paranaix Paranaix added a commit to Paranaix/tornado that referenced this issue Feb 3, 2015

@Paranaix Paranaix Added a "default" block solving #703 0dab95b

great, that's what i want, thx all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment