How to pass variables to assets in Flask - flask

I'm using Flask to build a website.
I also use assets to manage my js and css resources.
Now I want to pass some variables to my js scripts.
here is the code I register assets when the flask init(__init__.py):
download_js = Bundle("applog/download.coffee", filters=["jinja2", "coffeescript"],
output="gen/js/download.js")
assets.register("download_js", download_js)
here is the code I use the asset in my template file(download.html):
{% assets "download_js" %}
<script>
require(["{{ ASSET_URL}}"]);
</script>
{% endassets %}
and in view file("view.py"), I pass the varibales like this:
return render_template("download.html", apps=apps, versions=versions)
and I want to use the variable "apps" in the js file like this:
DownLoadSelector("appList", {{ apps }})
How can I do that?

Your assets are static, you can't change it in an easy way. You can add a filter to webassets, but it is a weird hack.
To do what you want, you can do it:
{% assets "download_js" %}
<script>
window.apps = {{ apps }};
require(["{{ ASSET_URL}}"]);
</script>
{% endassets %}
In your code, you just call apps:
DownLoadSelector("appList", window.apps)

Related

KeyCDN and DO Spaces: Django {% static %} vs {{ STATIC_URL}} when STATICFILES_STORAGE is set

I am using digitalocean.com spaces to store static files for my Django app. I set it up successfully according to their tutorial (same settings as AWS). I now want to put a CDN in front of the static files. KeyCDN has a document describing how to do this but suggests using {{STATIC_URL}} in templates rather than the {% static %} templatetag.
Django admin uses the {% static %} templatetag not {{ STATIC_URL}}. In some cases there is no difference, however, if you define STATICFILES_STORAGE, as is required to store static files in digitalocean.com spaces, the templatetag {% static %} ignores whatever you explicitly declare in settings.py for STATIC_URL.
I have:
STATICFILES_STORAGE='storages.backends.s3boto3.S3Boto3Storage'
S3Boto3Storage sets the template tag {% static %} to point to https://ams3.digitalocean.com/bucket_name/path/to/static/ regardless of the setting of {{ STATIC_URL }}.
Manually setting STATIC_URL= in settings.py as KeyCDN suggests:
STATIC_URL = 'http://keycdndjango-1c6b.kxcdn.com/static/'
has no effect on what the templatetag {% static %} returns.
So i cannot figure out how to make KeyCDN work with this setup.
Any help is appreciated!
Well, I don't know if this was the case, but I'm using Digital Ocean CDN and setting AWS_S3_ADDRESSING_STYLE to 'virtual' made the change
from
https://ams3.digitalocean.com/bucket_name/path/to/static/
to
https://bucket_name.ams3.digitalocean.com/path/to/static/

Offline context with Wagtail Page data (Django-Compressor)

I've got Wagtail set up with Django-Compressor (COMPRESS OFFLINE = True) which all works except for one template.
This template uses the Disqus plugin which requires:
An absolute page url
A unique page identifier
In my template I have included the following:
{% compress js inline %}
// My JS Code
this.page.url = "{{ page.full_url }}";
this.page.identifier = {{ page.id }};
{% endcompress %
So when accessing the page I get the error You have offline compression enabled but key "ARANDOMKEYGOESHERE" is missing from offline manifest. As per the Django-Compressor docs:
If you use any variables inside the {% compress %} blocks, make sure to list all values you require in COMPRESS_OFFLINE_CONTEXT
How would I go about adding the Page instance to the context in my settings? I thought of something like (pseudo-code):
COMPRESS_OFFLINE_CONTEXT = { 'page': request.get('page') }

How can I include template tags in static files in Django?

I would like to be able to DRY out my static files by using a template tag, like {% url 'my_view' %}, in my static file, instead of /path/to/my_view. Is there a way to do this?
Short answer is no. But you can circumvent this, there's two approaches I can think of:
add a script with the urls you need in your base html template, they need to be available globally so that you can access them with other scripts
make a script to generate a .js file with all your urls and place it with all the other staticfiles (django translations for js use a similar approach)
Approach 1, would be something like:
<html>
...
<script>
var myApp = {
URLS: {
login: {% url 'login' %},
welcome: {% url 'welcome' %},
...
}
}
</script>
<script>console.log("The login url is " + myApp.URLS.login + "!")</script>
<script src="script/that/uses/urls.js"></script>
...
</html>

Angular JS + Django - Referencing static files

I've written my first angular app for handling a rather complex multi-file upload process within a Django app. Everything is working great and I'm loving Angular. However, I stumbled on a simple problem referencing image sources. It's not critical for my app, but I wanted to add a simple spinner/whirligig image while the files are uploading.
In my non-Angular Django templates this is dead simple:
<img src='{% static 'whirligig.gif' %}'>
This doesn't work inside Angular views due to the Angular/Django template syntax conflict. Of course, I can hard-code my Django STATIC_URL path or use a relative path from the Angular partial, but I'd prefer not to. Am I missing something simple here or is this just an unfortunate product of mixing two MVC frameworks?
Have you tried verbatim tag?
I guess you can do something like:
{% verbatim %}{{ {% endberbatim %}{% static 'whirligig.gif' %}{% verbatim %} }}{% endverbatim %}

Handlebars.js in Django templates

I need a javascript templating system and i think handlebars.js does an excellent job in this case.
I'm having syntax conflicts with handlebars templates inside a django template because django tries to render handlebars variables.
Is there a tag in django templates to stop rendering a block with curly braces?
Something like:
{{ django_context_varable }} #works
{{% raw %}}
<script id="restaurants-tpl" type="text/x-handlebars-template">
<ul>
{{#restaurants}} #not rendered by django, plain text
<li>{{name}}</li>
{{/restaurants}}
</ul>
</script>
{{% endraw %}}
Edit
Likely i found this. It works fine.
Update
Django 1.5 supports verbatim tag natively.
I use a custom template tag for another js templating system, here:
https://gist.github.com/629508
Use in template:
{% load mytags %}
{% verbatim %}
{{ This won't be touched by {% django's %} template system }}
{% endverbatim %}
Edit: This custom template tag is no longer necessary, as Django's template language now supports the {% verbatim %} template tag.
Is there a tag in django templates to stop rendering a block with curly braces?
OLD Answer for Django 1.0-1.4: No, though you could though you could put the block in a separate file and include it without rendering or use a different templating engine.
New Answer: The answer above was correct in August 2011 when the question was asked and answered. Starting in Django 1.5 (released Feb 2013, though alpha/beta versions in late 2012), they introduced the {% verbatim %} and {% endverbatim %} which will prevent the django template engine from processing the content in the block.
So for the question asked the following will work in django 1.5+ out of the box:
{{ django_context_varable }} #works
{% verbatim %}
<script id="restaurants-tpl" type="text/x-handlebars-template">
<ul>
{{#restaurants}} #not rendered by django, plain text
<li>{{name}}</li>
{{/restaurants}}
</ul>
</script>
{% endverbatim %}
The documentation on verbatim is here. Yes, this was noted by others earlier, but as this is the accepted answer I should list the easiest solution.
I wrote a very small django application : django-templatetag-handlebars exactly for that purpose.
{% load templatetag_handlebars %}
{% tplhandlebars "tpl-infos" %}
{{total}} {% trans "result(s)." %}
<p>{% trans "Min" %}: {{min}}</p>
<p>{% trans "Max" %}: {{max}}</p>
{% endtplhandlebars %}
Render your block as usual using Handlebars.js API :
var properties = {
total: 10,
min: 5,
max: 4
};
var template = Handlebars.compile($('#tpl-infos').html()),
rendered = template(properties);
I wrote it the day #chrisv published its package, with a KISS approach in mind. It is mainly based on Miguel Araujo's gist : https://gist.github.com/893408.
for a deeper integration between handlebars and Django (including optional on-the-fly precompilation) check out my project at
https://bitbucket.org/chrisv/django-handlebars/
It basically works like this:
create HB template under
appdirectory/hbtemplates/myapp/template.html
(just like Django template)
in your app, use
{% handlebars myapp %}
template tag and render template like so:
Handlebars.templates["myapp.template.html"]({context:"value"});
Compile your handlebars first!
From handlebars precompiling documentation:
In addition to reducing the download size, eliminating client-side compilation will significantly speed up boot time, as compilation is the most expensive part of Handlebars.
You can compile templates in your build environment using handlebars npm module, or integrate it with a build tool like gulp with gulp-handlebars.
After compiling, your handlebars templates can be served as static resources and bypass server side rendering altogether. Makes it easier on caching too :)
Typical usage would look like this:
<div id="restaurants-tpl">
Waiting for content...
</div>
<script src="{% static 'js/handlebars.runtime.js' %}"></script>
<script src="{% static 'js/templates.js' %}"></script>
<script>
// Let django render this as a json string
properties = {{ properties }};
// Use Handlebars compiled template imported above
rendered_html = Handlebars.templates["restaurants-tpl"](properties);
// Set element content
document.getElementById("restaurants-tpl").innerHTLM = rendered_html;
</script>
Django's templating system doesn't support escaping blocks at a time. It would be easy to work around were it not for the fact that when templates are processed the tokenizer doesn't keep exact information on what the tokens looked like before they got tokenized.
I have used the following work-around which is ugly, but (sort of) works. Use different tag delimiters in your templates and a django template tag that translates those back to what you actually want:
#register.tag(name="jstemplate")
def do_jstemplate(parser, token):
while self.tokens:
token = self.next_token()
if token.token_type == TOKEN_BLOCK and token.contents == endtag:
return
self.unclosed_block_tag([endtag])
nodelist = parser.parse( ('endjstemplate',) )
parser.delete_first_token()
s = token.split_contents()
tmpl_id = Variable( s[1] ) if (len(s) == 2 and s[1]) else ''
return JsTemplateNode( nodelist, tmpl_id )
class JsTemplateNode(template.Node):
def __init__(self, nodelist, tmpl_id=''):
self.tmpl_id = tmpl_id
self.nodelist = nodelist
def render(self, context):
content = self.nodelist.render(context)
return u'<script id="%s" type="text/x-handlebars-template">%s</script>' % (
self.tmpl_id.resolve(context),
re.sub( ur'{\$(.*?)\$}', u'{{\\1}}', content ), )
For bonus points you can leverage Django's templates within your templates ...
which will probably cook your brain trying to untangle later:
{% jstemplate "restaurants-tpl" %}
{$#restaurants$}
<div id="<$name$<" class="{$type$}">
<ul class="info">
{$#if info/price_range$}<li><em>{{ trans "Price Range" }}:</em> {$info/price_range$}</li>{$/if$}
{$#if info/awards$}<li><em>{{ trans "Awards" }}:</em> {$info/awards$}{$/if$}
</ul>
<div class="options">
<button>{% trans "Reservation" %}</button>
</div>
</div>
{$/restaurants$}
{% jstemplate %}
Actually I wrote a custom template filter which goes like this:
from django import template
register = template.Library()
def handlebars(value):
return '{{%s}}' % value
register.filter('handlebars', handlebars)
and use it in a template like so:
{{"this.is.a.handlebars.variable"|handlebars}}
It's the simplest thing I could think of. You just have to put your handlebars variable name in quotes. I regret I hadn't got this idea before I struggled with ssi. It works also with keywords:
{{"#each items"|handlebars}}
Why not use jinja2 instead? IMO, they're both elegant to use. Here's an excellent article about it: Using Jinja2 with Django