8

Summary:

How should I reference static files in a handlebars-part in a django template? I can use handlebars if I use verbatim tags, but then I can't use django's static tag.

Details

While converting an app to Django, I came across a part that uses handelbars.js for rendering ajax-call-results. Via, amongst others, "Handlebars.js in Django templates" I found out about the {% verbatim %} tag.

A simple piece of handlebars works fine with this. But I also have a part where images are dynamically shown based on the result, which looks something like this:

<img src="path/{{ result }}.png">

Now while this works fine if I set the path manually, I believe in Django it is good practice to reference your static files like so:

<img src="{% static 'path/file.png' %}">

Just getting a static_url constant isn't advised, see for instance this blog

So unless someone has a real compelling reason to fix it otherwise, I believe it is best to use the {% static %} method.

The naive solution would be to combine the 2 techniques, and literally spray the template with verbatim/endverbatim. Apart from the fact that this looks ugly, illegible and seems like a bad idea from the start, it also doesn't work.

{% verbatim %}
    <!-- handlebars -->
    {% endverbatim %}
    <img src="{% static 'path{% verbatim %}{{ result }}{% endverbatim %}' %}">
    {% verbatim %}
    <!-- handlebars -->
{% endverbatim %}

This ends in tears, as the result is

TemplateSyntaxError at /
Could not parse the remainder: ''path{%' from ''path{%'

It might be possible to generate the correct static url on the backend side, and render that. But the backend shouldn't be aware of what image we want to show in the template.

Only solution might be to do an extra call to the backend with the 'relative' string (e.g. path/result.png) to the backend, and ask for the correct static link? This isn't that hard, but requires an extra call, which shouldn't be the case.

So how do I correctly reference these static files ?

Community
  • 1
  • 1
Nanne
  • 64,065
  • 16
  • 119
  • 163
  • The arguments against the use of `STATIC_URL` in the blog post you link to don't seem that relevant to your use case. In fact, I would argue the opposite because you explicitly want only the static URL prefix. The rest of the URL (the file name portion) is being generated on the client side by your handlebars template. Note also that there is a [`get_static_prefix`](https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#get-static-prefix) template tag which wraps `STATIC_URL` for you. – solarissmoke Jul 09 '16 at 11:09
  • I'm not sure I agree. I want a variable part of an image (the name part) that comes from json, and is parsed by handlebars. But that image is served as a static file by django, so I want django to decide what would actually go on there. There's no reason that caching example in the bottom of the link isn't valid in my situation -> If I want to cache them then handlebars wouldn't know about it. So in the end handlebars would only know about the 'relative' part of the static file, and as far as I can see, all the arguments in that blog are relevant? – Nanne Jul 09 '16 at 11:16
  • Then it is important to use proper static URL generation for the JSON? I don't see how it helps for the handlebar template were the actual file path (which is what caching/different storage backend/etc would modify) is a generated client side. – solarissmoke Jul 09 '16 at 11:26
  • So that would mean to generate the complete link in the JSON, something i'd rather not do, as it is not the models responsibility to know about those images.... – Nanne Jul 09 '16 at 11:37
  • How prevalent is your handlebars code? If there is just a little, you could use the [templatetag](https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#templatetag) tag to encode it... – Peter Brittain Jul 14 '16 at 22:30
  • It's quite a lot, but this does sound like a workable solution for some people? Maybe put it in an answer and add a small example, as it sounds like a good one.. – Nanne Jul 15 '16 at 07:06

2 Answers2

3

You’d like to not delineate the boundary between handlebar tags and Django tags. Perhaps the cleanest solution is to explicitly declare handlebar tags as so:

{{ "handlebars_variable"|handlebars }}

where the filter handlebars is defined as so (source):

from django import template
register = template.Library()

@register.filter
def handlebars(value):
    # str.format would require ugly escaping, so we use '%'
    return '{{%s}}' % value

But that’s not enough: You want to pass a handlebars tag to static, and even with the filter you can’t do that directly. But perhaps you could try using with:

{% with "handlebars_variable"|handlebars as handlebars_tag %}
  <img src="{% static handlebars_tag %}">
{% endwith %}

But even that’s not enough. You want to prepend path/. There are multiple options for you:

  • You could use the add filter based on this answer and nested with statements (ugh).
  • You could define a template tag called setvar like done so here (if you’d like).
  • You could define an ad hoc template tag like this (perhaps inelegant):

    @register.filter
    def static_result_path(value):
        return 'result/{{%s}}' % value   
    

    and then change the template code to:

    <img src="{% static "handlebars_variable"|static_result_path %}">
    
  • Use get_static_prefix (the simplest!):

    <img src="{% get_static_prefix %}result/{{ "handlebars_variable"|handlebars }}" />
    
  • (And there’s always Jinja.)

Community
  • 1
  • 1
Yatharth Agarwal
  • 4,385
  • 2
  • 24
  • 53
  • It really looks good, but i couldn't get it to work yesterday. This was mainly because of little time to debug so I think this might be a good one! – Nanne Jul 15 '16 at 07:07
  • It was mostly different set-up issues or typos, at least the first ones I dealt with :). I must admit that there might have been some Nianticlabs-game come between me and fixing this, but marking you as correct :D – Nanne Jul 18 '16 at 07:12
1

Even though django templates don't support any sort of escape character, they do support the templatetag tag that allows you to embed the special text in this case.

Assuming you don't have too many handlebars substitutions, you could just do something like this as needed:

<img src="{% get_static_prefix %}path/{% templatetag openvariable %} result {% templatetag closevariable %}.png" />

However, if you have a lot of substitutions to do, using a custom filter as per yarthathrock's answer is more succinct and so probably easier to maintain in the long run.

Peter Brittain
  • 13,489
  • 3
  • 41
  • 57