I want to render some static files (*.js in particularly) using Django template variables. I believe this is a common use-case, especially when doing anything AJAX-y; I don't want to hardcode AJAX urls in my .js files any more than I want to hardcode them in my .html files. Buuuut of course I don't want those static files to have to run through the template engine at every client request because this will be slow. I am referring to things like URLs (which do not change after compile/deploy) or static (non-db) model attributes. (I suppose there are use cases where these things might be changed at run-time - this is Python, after all- but I think they are uncommon). For some possible template variables (e.g. model fields), of course the file must be rendered at the time of the client request, but this is not what I'm talking about.
So wouldn't it make sense to render some of my static files through the template engine, for a subset of possible template variables, perhaps at the same time as collectstatic
?
As far as I can tell this is not currently the case. To be clear, what I am looking for is a solution to render static files through the template engine at compile/deploy-time so that at "client-request-time" they are in fact plain old static files.
Such an approach would avoid these hacks:
Disclaimers:
So:
collectstatic
(like a pre-collectstatic hook) that would allow one to render certain static files through the template engine before "collecting" them?EDIT: No responses yet...is this a really dumb question, and I'm missing something obvious? If so...go ahead and let me know...
There are several frameworks for Django for same purpose: django-pipeline, django-assets, and etc. which integrates different static files processing strategies, with varying degrees of difficulty configuring.
I use an external tool - Grunt (it requires node.js) - for asset post-processing after collectstatic
. It is easier and has a lots of plugins for any purpose (source validation, css/js/images minification, merging, testing and etc.).
It is possible to hook in collectstatic
by a custom static files storage with overrided post_process method.
example/settings.py
STATIC_ROOT = 'assets'
STATICFILES_STORAGE = 'example.storage.MyStaticFilesStorage'
example/storage.py
import os
from django.contrib.staticfiles.storage import StaticFilesStorage
from django.core.files.base import ContentFile
from django.template import Template, Context
class MyStaticFilesStorage(StaticFilesStorage):
def post_process(self, paths, dry_run=False, **options):
# don't even dare to process the files if we're in dry run mode
if dry_run:
return
js_template_data = {'foo': 'bar'} # template variables
js_template_extension = '.jst'
js_extension = '.js'
for original_name, (storage, path) in paths.items():
processed = False
saved_name = original_name
original_path, original_extension = os.path.splitext(original_name)
if original_extension == js_template_extension:
with storage.open(path) as original_file:
saved_name = original_path + js_extension
if hasattr(original_file, 'seek'):
original_file.seek(0)
original_source = original_file.read()
c = Context(js_template_data)
saved_source = Template(original_source).render(c)
self.delete(saved_name)
self.delete(original_name)
self._save(saved_name, ContentFile(saved_source))
processed = True
yield original_name, saved_name, processed
A completely different way to approach the problem would be to ask if you really need to get those URLs in javascript--instead, can the Javascript get the URLs from things like data attributes in your HTML?
In other words, you might have wanted:
homepage.html:
<div id="pop-up-modal">pop me up</div>
homepage.js:
$("#pop-up-modal").click(function {
$.ajax("{% url 'some-class-name %}")
...
});
When it can often be more straightforward to do something like:
homagepage.html:
<div id="pop-up-modal" data-popurl="{% url 'some-class-name' %}">pop me up</div>
homepage.js:
$("#pop-up-modal").click(function {
$.ajax($(this).data('popurl'))
...
});
I think that django-medusa would suit your needs.
By setting up a renderer and using the disk based backend, generating the static files would be as easy as:
django-admin.py staticsitegen
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With