cundi / blog

push issues as a blog
2 stars 0 forks source link

理解Django的模板片段缓存[翻译] #36

Open cundi opened 8 years ago

cundi commented 8 years ago

Template fragment caching gotchas

By : Akshar Raaj

Variables in cached template fragment 缓存在模板片段中的变量

Assuming this is in template.

假设模板中包含一下内容。

{% cache 300 nums %}
{% for i in nums %}
    <p>i</p>
{% endfor %}
{% endcache %}

And assuming we send {'nums': range(100)} from context, then 0 to 99 will be sent in the response.

Now suppose we change context to {'nums': range(1000)}, still for next 5 minutes i.e until the cache expires, 0 to 99 will be sent in the response. 0 to 999 will not be sent in the response.

To fix this, we should use the variable too with the {% cache %} tag. So correct code would be

为了修复这个问题,我们应该使用 {% cache %} 标签。修正的代码为:

{% cache 300 nums_cache nums %}
{% for i in nums %}
    <p>i</p>
{% endfor %}
{% endcache %}

After this whenever context nums changes, cache would be reevaluated.

Boolean variable in cached template fragment

Assuming template contains

{% cache 300 hello %}
{% if hello %}
  <p>Hello</p>
{% endif %}
{% endcache %}

and assuming {'hello': True} is sent in context. Then <p>Hello</p> will be sent in response.

Now even when we send {'hello': False} in context, <p>Hello</p> will still be sent in response because it's already cached.

To fix this.

{% cache 300 hello_cache hello %}
{% if hello %}
  <p>Hello</p>
{% endif %}
{% endcache %}

request.user in cached template fragment

{% cache 300 username_cache %}
<p>{{request.user.username}}</p>
{% endcache %}

When current user logs out and a new user logs in, still the username of old user is shown on the web page because template fragment is already cached and would not be reevaluated.

在当前用户登出,新用户登录后,之前老用户的用户名仍旧显示在网页上,因为模板片段已经缓存了而且不会再去重新计算。

Fix it like
像这样修正它:

{% cache 300 username_cache request.user.username %}
<p>{{request.user.username}}</p>
{% endcache %}

Gotcha while using base template 理解基础模板的使用

Assuming we are using template inheritance, and our base template i.e base.html looks like:

假设我们正在使用模板继承,我们的基本模板,比如 base.html的内容如下:

{% load cache %}
<html>
    <head>
    </head>
    <body>
    {% cache 300 base_body %}
    {% block body %}
    {% endblock %}
    {% endcache %}
    </body>
</html>

And the child template, say test.html looks like

另外一个子模板test.html 的内容如下:

{% extends "base.html" %}
{% load cache %}
{% block body %}
  {% cache 300 username request.user.username %}
    <p>{{request.user.username}}</p>
  {% endcache %}
{% endblock %}

Assuming our view uses test.html. Suppose cache is empty now, and you are logged in as user1 and then you make the request to a url which uses test.html. So response will contain <p>user1</p>.

假设视图使用的是test.html。假定当前缓存是空的,你以user1的身份登录进去,然后去请求一个使用test.html的url。那么,相应将包含 <p>user1</p>

Now if you logout and login as user2 and make the request, still the response will be <p>user1</p> instead of <p>user2</p>.

假如现在你登出去了,然后以登录user2的身份

The reason for this is, as per Django docs.

The extends tag is the key here. It tells the template engine that this template “extends” another template. When the template system evaluates this template, first it locates the parent – in this case, “base.html”.

But in our case, the parent template itself has some cached content, which Django will use. Django will not even bother to look at the {% block body %} of child template if it finds cached content base_body for the parent template.

The fix for this is to differentiate the cache of different users even in the base template. So we could change the base template to look like.

{% load cache %}
<html>
    <head>
    </head>
    <body>
    {% cache 300 base_body request.user.username %}
    {% block body %}
    {% endblock %}
    {% endcache %}
    </body>
</html>

After this, if user1 is logged in the <p>user1</p> is sent in response. If user2 is logged in then <p>user2</p> is sent in response.

Gotcha with {% include %} tag.

It is similar to the gotcha of template inheritance discussed in last section.

Assuming the view uses test.html, which contains.

{% cache 60 body_cache %}
{% include "body.html" %}
{% endcache %}

And body.html contains

<p>Hello {{request.user.username}}</p>

So when first user, say user1 logs in, cache is evaluated and

Hello user1

is sent in response. When user2 logs in, still

Hello user2

will be sent in response.

To fix this, test.html should also use all the variables on which included template depends.

So code in test.html should change to

{% cache 60 body_cache request.user %}
{% include "body.html" %}
{% endcache %}

If included template, i.e body.html depended on any other variable, that other variable too should be used with {% cache %} tag.