如何高效地在Django中渲染图片?

0 投票
1 回答
3416 浏览
提问于 2025-04-18 05:39

我正在写一个小的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 个回答

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>

撰写回答