如何使用Flask / Python / Jinja提前刷新

时间:2014-11-26 23:18:50

标签: flask jinja2

您可以通过立即发送HTML响应的第一部分(例如包含JS / CSS链接的<head>..</head>)来使网站看起来更快,同时计算其余的响应。 (见http://www.stevesouders.com/blog/2009/05/18/flushing-the-document-early/

在Flask中执行此操作的好方法是什么?

我看到Flask支持流媒体(http://flask.pocoo.org/docs/0.10/patterns/streaming/),所以我认为它应该是可能的,但我想知道是否有人找到了一种干净的方法将所有部分拼接在一起。例如,如何构建Jinja模板以便可以提前提取/刷新文档片段?

1 个答案:

答案 0 :(得分:0)

这并不完美,但我正在尝试以下方面。我有一个装饰师:

def early_flush_of_head(template_name):
    def wrapper(original_view_function):

        @wraps(original_view_function)
        def new_view_function(*args, **kwargs):
            def streamer():
                yield render_template(template_name, head_only=True)
                yield original_view_function(*args, **kwargs)

            return Response(stream_with_context(streamer()))
        return new_view_function
    return wrapper

您可以使用它来装饰这样的给定视图:

@app.route('/')
@early_flush_of_head('template.html')
def index():
    data = something_time_consuming()  # DB traffic or maybe some crazy calculations

    return render_template('template.html', data=data)

每个template.html都是这样的:

{% extends "base.html" %}

{% block pre_flush_head %}
    <link href="static/css/page.min.css" rel="stylesheet">
    <script src="static/js/page.min.js"></script>
{% endblock %}

{% block post_flush_head %}
    <title>{{ page_name }}</title>
{% endblock %}

{% block content %}
    The actual page.
{% endblock %}

base.html看起来像这样:

{% if head_only %}
<!DOCTYPE html>
<html lang="en">
<head>
        <link href="static/css/common.min.css" rel="stylesheet">
        <script src="static/js/common.min.js"></script>
{% else %}
    {% block post_flush_head %}{% endblock %}
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>
{% endif %}

每个模板实际渲染两次。一旦在装饰器中使用head_only = True,那么再次在实际视图函数中没有定义。还要注意,我没有冲洗整个头部,有一些东西在头部,但仍然需要来自真实视图功能的数据。如果您根据数据命名页面,标题就是一个很好的例子。

这里有一些改进空间(我不喜欢你必须将模板的名称放两次,而且它总体上有点干扰),但它确实可以让你获得早期冲洗的好处(make确保您的部署环境在您不知情的情况下不会缓冲。)