Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference static files in a handlebars-django template

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 ?

like image 702
Nanne Avatar asked Jul 09 '16 09:07

Nanne


People also ask

How does Django find static files?

Using the collectstatic command, Django looks for all static files in your apps and collects them wherever you told it to, i.e. the STATIC_ROOT . In our case, we are telling Django that when we run python manage.py collectstatic , gather all static files into a folder called staticfiles in our project root directory.


Video Answer


2 Answers

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.)

like image 186
Yatharth Agarwal Avatar answered Sep 20 '22 03:09

Yatharth Agarwal


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.

like image 42
Peter Brittain Avatar answered Sep 21 '22 03:09

Peter Brittain