如何高效地在Django中渲染图片?
我正在写一个小的Django应用程序来处理图片。
我希望这个应用尽量做到“干净整洁”,所以这是我的目标:
用户上传一个文件,并填写一些字段,比如标题、替代文本、描述等。
在模板中,我希望能够做一些类似于:
model.image.render_tag
这样就能输出类似于:
<img src='path/image.jpg' title='title' alt_text='alt_text..' />
问题是,这行代码应该放在模板里,这样如果开发者需要添加或删除某些内容,他们只需编辑模板,所有渲染的图片都会随之改变。
也可以添加第二个模板来渲染那个模板。
现在,有几种方法可以实现这个目标:
1)
直接包含一个模板,这个模板渲染一个带命名空间的变量,并强制开发者每次都“更改”图片变量的名称,模板大概是这样的:
<img src="{{ namespaced_image.raw.path }}" alt_text="{{ namespaced_image.alt_text }}"... />
在这种情况下,开发者在包含路径之前应该把图片重命名为带命名空间的版本。
像这样:
{% with namespaced_image=image %}
{% include images/template.html %}
{% end with %}
2)
添加一个模板标签来渲染图片,基于用户可以在设置中编辑的原始字符串,像这样:
settings.py
namespaced_image_tag="<img src={path} ... />"
而我的模板标签会做类似这样的事情:
@register
def rendered_tag(image)
return namespaced_image_tag.format(path=image.raw.path, ...)
这样开发者只需添加自定义标签文件并使用:
{% load images_filters %}
{{ image|rendered_tag }}
3)
以上方法的结合:
会有一个默认的template.html,里面包含标签,还有一个模板标签,通过给它命名空间的图片作为上下文来渲染模板。
@register
def rendered_tag(image, template="default_template.html")
return render_template(template, namespaced_image=image)
这样开发者可以做类似于:
{% load images_filters %}
{{ image|rendered_tag }}
{{ image|rendered_tag:"custom_template_name" }}
不过,我不太清楚每次请求渲染多个模板会对性能产生什么影响。
另外,我不太喜欢选项#1,因为它不够实用和可读。
选项#2也不好,因为我不能使用不同的“模板”,也不能扩展其他模板。我也不太喜欢模板标签,特别是因为用户必须在每个使用的模板中导入这个文件。
选项#3在可用性方面是最好的,但我觉得这会对性能产生很大影响。有什么建议吗?
1 个回答
在我看来,很多人可能也和我有同样的看法,一个模型不应该负责它在HTML中的表现,所以我觉得有 model.image.render_tag
这个东西是不太对的。
在一个应用程序中,只有视图和它们的模板才应该知道如何把东西表现成HTML。
你可以有一个辅助函数来生成图片的HTML,然后在你的视图中使用它。你也可以有一个 simple_tag
来引用这个函数,这样你就可以在模板中使用它。
如果在模板中调用这个函数的性能有问题,可以考虑使用性能更好的模板引擎——你可以参考这个 SO回答 来了解不同模板引擎的性能对比,或者你可以在视图中调用这个辅助函数,然后通过上下文把结果传递给模板。
更新
我将通过一个例子来演示我上面所说的内容。
# inside html_utils.py
def image_to_html(image):
return '<img src="%(path)s" title="%(title)s" alt="%(alt)s" />' % {
'path': image.raw.path,
'title': image.title,
'alt': image.alt_text
}
# inside html_template_utils.py
import html_utils
from django import template
register = template.Library()
@register.simple_tag
def image_tag(image):
return html_utils.image_to_html(image)
{# inside images_template.html #}
{% load html_template_utils %}
<div class="images-container">
{% for image in images %}
{% image_tag image %}
{% endfor %}
</div>
上面的代码通过使用我们创建的 image_tag
simple_tag
从模板中调用了 image_to_html
辅助函数。另一种可能的方式是直接在视图中调用 image_to_html
,然后把结果传递给模板:
# inside views.py
import html_utils
def view_images(request):
# ...
images_html = [html_utils.image_to_html(image) for image in images]
# ...
return render_to_response('images_template.html', {
'images_html': images_html
}, context_instance=RequestContext(request))
{# inside images_template.html #}
<div class="images-container">
{% for image_html in images_html %}
{{ image_html }}
{% endfor %}
</div>