Django:在部署时通过模板引擎呈现静态文件

时间:2014-02-09 18:16:00

标签: javascript python django templates deployment

我想使用Django模板变量渲染一些静态文件(特别是* .js)。我相信这是一个常见的用例,尤其是在做任何AJAX-y时;我不想在我的.js文件中硬编码AJAX网址,只是想在我的.html文件中对它们进行硬编码。 Buuuut当然我不希望那些静态文件在每个客户端请求都必须通过模板引擎运行,因为这会很慢。我指的是诸如URL(在编译/部署之后不会改变)或静态(非db)模型属性之类的东西。 (我想有些用例可能会在运行时更改这些内容 - 毕竟这是Python,但我认为它们并不常见)。对于一些可能的模板变量(例如模型字段),当然必须在客户端请求时呈现文件,但这不是我所说的。

因此,通过模板引擎渲染一些静态文件,对于可能的模板变量的子集,可能与collectstatic同时进行渲染是不合理的?

据我所知,目前情况并非如此。要明确的是,我正在寻找的是在编译/部署时通过模板引擎呈现静态文件的解决方案,以便在“客户端请求时”它们实际上是普通的旧静态文件

这种方法可以避免这些黑客攻击:

免责声明:

  • 是的我知道有javascript的模板引擎(小胡子,把手,原型等)。当Django已经有一个时,我为什么要将另一个模板引擎添加到堆栈?加上语法冲突!这看起来很傻。
  • This看起来很难解决它,但它很复杂而且没有完全实现。

所以:

  1. 那里有解决方案吗?
  2. 如果没有,有没有办法挂钩collectstatic(就像一个pre-collectstatic钩子),允许人们在“收集”它们之前通过模板引擎渲染某些静态文件?
  3. 修改: 还没有回复......这是一个非常愚蠢的问题,我错过了一些明显的东西吗?如果是这样......继续告诉我......

4 个答案:

答案 0 :(得分:3)

  1. Django有几个用于相同目的的框架:django-pipelinedjango-assets等,它们集成了不同的静态文件处理策略,配置有不同程度的难度。
    我使用外部工具 - Grunt(它需要node.js) - 用于collectstatic之后的资产后处理。它更容易,并且有很多plugins用于任何目的(源验证,css / js /图像缩小,合并,测试等)。

  2. 可以使用覆盖的post_process方法通过自定义静态文件存储挂钩collectstatic

  3. 示例/ settings.py

    STATIC_ROOT = 'assets'
    STATICFILES_STORAGE = 'example.storage.MyStaticFilesStorage'
    

    示例/ 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
    

答案 1 :(得分:3)

解决问题的一种完全不同的方法是询问您是否确实需要在javascript中获取这些网址 - 相反,Javascript是否可以从HTML中的数据属性中获取网址?

换句话说,你可能想要:

<强> homepage.html

<div id="pop-up-modal">pop me up</div>

<强> homepage.js

$("#pop-up-modal").click(function {
  $.ajax("{% url 'some-class-name %}") 
  ...
});

通常可以更直接地执行以下操作:

<强> 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')) 
  ...
});

答案 2 :(得分:1)

我认为django-medusa符合您的需求。

通过设置渲染器并使用基于磁盘的后端,生成静态文件将非常简单:

django-admin.py staticsitegen

答案 3 :(得分:0)

你没有疯。我也对此感到沮丧,并发现自己在为我处理的每个新 Django 项目编写一些东西。我认为缺乏直接解决方案的原因是这是特大干旱的骨干。对这些东西进行硬编码并称之为一天是非常容易的。这和两个最常见的用例涉及从另一种语言的代码生成一种语言的代码,这往往被视为可疑。

我最近发布了一个新的 Django 包 django-render-static,它一般地解决了这个问题。它搭载在 Django 现有的模板引擎基础架构上。一个名为 render_static 的管理命令应该在 before collectstatic 之前运行。此命令将查找在设置中注册(或作为参数传递)的模板,并将它们呈现到磁盘上的静态文件位置。然后它们可用于您配置的任何普通静态文件打包管道。

我确信还有更多用例,但我发现的两个最常见的是在静态 JavaScript 中提供一个 reverse 实用程序,它相当于 Django 和自动翻译定义的 Python 结构(即选择字段)转换为 JavaScript。该应用提供了两种模板标签。

JavaScript url 反转代码保证在功能上等同于 Django 的 reverse 函数。因为it's been well documented