简体   繁体   English

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

[英]Django: render staticfiles through template engine at deploy-time

I want to render some static files (*.js in particularly) using Django template variables.我想使用 Django 模板变量呈现一些静态文件(特别是 *.js)。 I believe this is a common use-case, especially when doing anything AJAX-y;我相信这是一个常见的用例,尤其是在做任何 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.我不想在我的 .js 文件中硬编码 AJAX url,就像我不想在我的 .html 文件中硬编码它们一样。 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.我指的是 URL(在编译/部署后不会改变)或静态(非数据库)模型属性之类的东西。 (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). (我想有些用例可能会在运行时更改这些东西——毕竟这是 Python——但我认为它们并不常见)。 For some possible template variables (eg 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 ?那么通过模板引擎渲染我的一些静态文件,对于可能的模板变量的子集,也许与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:免责声明:

  • Yes I know there are template engines out there for javascript (mustache, handlebars, prototype, etc).是的,我知道有用于 javascript 的模板引擎(mustache、handlebars、prototype 等)。 Why should I add another template engine to the stack when Django already has one?当 Django 已经有一个模板引擎时,为什么要向堆栈添加另一个模板引擎? Plus the syntax collides!加上语法冲突! That seems silly.这看起来很傻。
  • This looks like it takes a crack at it, but it's complicated and not fully implemented. 看起来需要破解,但它很复杂并且没有完全实现。

So:所以:

  1. Is there a solution out there that I am missing?有没有我缺少的解决方案?
  2. If not, is there a way to hook into collectstatic (like a pre-collectstatic hook) that would allow one to render certain static files through the template engine before "collecting" them?如果没有,有没有办法挂钩collectstatic (如 pre-collectstatic 挂钩),允许人们在“收集”它们之前通过模板引擎呈现某些静态文件?

EDIT : No responses yet...is this a really dumb question, and I'm missing something obvious?编辑:还没有回应......这是一个非常愚蠢的问题,我错过了一些明显的东西吗? If so...go ahead and let me know...如果是这样......继续让我知道......

  1. 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. django有几个框架用于相同的目的: django-pipelinedjango-assets等,它们集成了不同的静态文件处理策略,配置难度不同。
    I use an external tool - Grunt (it requires node.js) - for asset post-processing after collectstatic .我使用外部工具 - Grunt (它需要 node.js) - 在collectstatic之后进行资产后处理。 It is easier and has a lots of plugins for any purpose (source validation, css/js/images minification, merging, testing and etc.).它更容易,并且有很多用于任何目的的插件(源验证、css/js/图像缩小、合并、测试等)。

  2. It is possible to hook in collectstatic by a custom static files storage with overrided post_process method.可以使用覆盖post_process方法的自定义静态文件存储挂钩collectstatic

example/settings.py示例/settings.py

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

example/storage.py示例/存储.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?解决该问题的一种完全不同的方法是询问您是否真的需要在 javascript 中获取这些 URL——相反,Javascript 能否从 HTML 中的数据属性等内容中获取 URL?

In other words, you might have wanted:换句话说,您可能想要:

homepage.html :主页.html :

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

homepage.js :主页.js :

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

When it can often be more straightforward to do something like:什么时候做这样的事情通常会更直接:

homagepage.html :主页.html :

<div id="pop-up-modal" data-popurl="{% url 'some-class-name' %}">pop me up</div>

homepage.js :主页.js :

$("#pop-up-modal").click(function {
  $.ajax($(this).data('popurl')) 
  ...
});

I think that django-medusa would suit your needs.我认为django-medusa会满足您的需求。

By setting up a renderer and using the disk based backend, generating the static files would be as easy as:通过设置渲染器并使用基于磁盘的后端,生成静态文件将非常简单:

django-admin.py staticsitegen

You aren't crazy.你没疯。 I was frustrated by this as well and found myself hacking something together for each new Django project I tackled.我也对此感到沮丧,并发现自己在为我处理的每个新 Django 项目编写一些东西。 I think the reason for the lack of direct solutions is that this is mega-drought bone DRY.我认为缺乏直接解决方案的原因是这是特大干旱的骨干。 Its super easy to just hard code these things and call it day.对这些东西进行硬编码并称之为一天是非常容易的。 This and the two most common use cases for this involve generating code in one language from code in another which tends to be viewed as suspect.这和两个最常见的用例涉及从另一种语言的代码生成一种语言的代码,这往往被视为可疑。

I've recently published a new Django package django-render-static that solves this problem generically.我最近发布了一个新的 Django 包django-render-static ,它一般地解决了这个问题。 It piggy-backs on Django's existing template engine infrastructure.它搭载在 Django 现有的模板引擎基础架构上。 A management command called render_static should be run before collectstatic .一个名为render_static的管理命令应该collectstatic之前运行。 This command will look for templates registered in settings (or passed as arguments) and render them to your static file location on disk.此命令将查找在设置中注册(或作为参数传递)的模板,并将它们呈现到磁盘上的静态文件位置。 They're then available for whatever normal static file packaging pipeline you have configured.然后它们可用于您配置的任何普通静态文件打包管道。

I'm sure there are more use cases, but the two most common I've found are providing a reverse utility in static JavaScript thats equivalent to Django's and auto-translating define-like python structures (ie choice fields) into JavaScript.我确信还有更多的用例,但我发现的两个最常见的是在静态 JavaScript 中提供一个reverse实用程序,相当于 Django 的和自动翻译类似定义的 python 结构(即选择字段)到 JavaScript。 The app provides template tags that do both.该应用程序提供了两者兼具的模板标签。

The JavaScript url reversal code is guaranteed to be functionally equivalent to Django's reverse function. JavaScript url 反转代码保证在功能上等同于 Django 的reverse功能。 I won't bother plopping example code down here because it's been well documented .我不会费心把示例代码放在这里,因为它已经被很好地记录了下来

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM