在Django的TEMPLATE_DIRS中使用外部URL

8 投票
3 回答
2548 浏览
提问于 2025-04-17 06:41

Django的设置文件Settings.py中的TEMPLATE_DIRS需要使用Unix风格的斜杠。

因此,当我在视图中调用

get_template('some/template.html')

时,结果总是从根目录开始,这导致调用了

/home/username/projectname/public/some/template.html

问题是我想使用托管在完全不同网站上的模板。对于其他设置字段(比如MEDIA_URL和STATIC_URL),这没有问题,它们可以接受绝对的http路径。

给定一个http路径,

 TEMPLATE_DIRS ('http://example.com/',)

在Settings.py中会强制

get_template('some/template.html')

在视图中尝试查找

/home/username/projectname/public/http://example.com/some/template.html

我尝试这样绕过这个问题

TEMPLATE_DIRS ('../../../../http://example.com/',)

但它仍然强制加上一个前导斜杠,所以我得到的是"/http://example.com",这没什么用。

我有几个问题:

  1. 有没有办法让它从另一个服务器拉取模板文件?
  2. 考虑到模板文件需要为视图处理,这样做可行吗?
  3. 有没有可能创建一个替代' django.template.loaders.filesystem.Loader'的东西,不需要Unix风格的斜杠?

3 个回答

0
  1. 不 - 你无法通过http从另一个服务器获取文件。
  2. 是的 - 你可以创建一个新的类,继承django.template.loaders.filesystem.Loader,并适当地修改load_template_source方法,这样就可以通过http加载模板了。

一旦你完成了第三步,那么第二步的答案就是“是的” - 这样做是可行的 - 最终Django的模板语言并不在乎文件来自哪里,只要格式正确就行。

不过,这样加载模板的方式似乎效率很低,更可能有更好的方法来实现同样的效果。

3

你不能这样做。

这和路径名称没有关系。其实是因为文件系统模板加载器需要从文件系统中加载东西,所以才叫这个名字。

这和MEDIA_URL的情况完全不同:MEDIA_URL只是把一个路径加到你的HTML里,然后浏览器会去加载这个路径的内容。Django并不关心那个文件放在哪里;实际上,如果你给它一个不是URL的文件路径(也就是没有通过某个网络服务器提供的路径),它根本就无法工作。

不过,你可以写一个模板加载器,从另一个服务器获取模板。模板加载器是可以插拔的——你只需要把新加载器的名字放到TEMPLATE_LOADERS设置里。这个加载器本身需要使用像urllib.urlopen这样的东西,从外部服务器获取模板。

但在你这么做之前,请仔细考虑。这意味着每一个模板请求现在都需要先调用外部服务器,才能提供页面。在一个典型的模板中,如果它扩展了其他模板并包含了一些模板标签的调用,这可能需要五到十次的调用。而且,与媒体文件不同,这个过程不能并行进行:页面在整个过程完成之前是无法提供的。这可能会让你的网络服务器变得非常非常慢。

我不知道你为什么觉得需要这样做。模板是你应用代码的一部分,所以它们通常和你的Python代码放在同一个服务器上。如果你真的有理由把它们放在外面,一个解决方案可能是通过像sshfs这样的方式,把外部文件系统挂载到你的网络服务器上。不过,这样做仍然可能会很慢。再想想吧。

5

如果你不想使用模板目录,其实可以不必使用。如果你的服务器可以提供模板文件,你可以直接通过 urllib2 从远程获取这些文件,然后手动创建和渲染模板。

import urllib2
from django.template import Context, Template

tpl_html = urllib2.urlopen("http://mysite.com")
tpl = Template(tpl_html)
return tpl.render(Context({
    'some_variable' : 'some_val',
})

不过,如果你打算这么做,就得加一些缓存,因为每次使用这个模板时,你都需要发起一次外部请求。另一种方法是写一个自定义加载器,但这样也会遇到同样的问题。

撰写回答