[IMP] qweb: document 't-cache' and 't-nocache' directives

related with: https://github.com/odoo/odoo/pull/88276

closes odoo/documentation#2056

Related: odoo/enterprise#27582
Related: odoo/upgrade#3451
Related: odoo/odoo#88276
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
Gorash 2022-05-13 12:01:11 +00:00
parent f477cf5f1c
commit 7c4656f0c4

View File

@ -491,6 +491,228 @@ Debugging
is equivalent to ``importlib.import_module("pdb").set_trace()`` is equivalent to ``importlib.import_module("pdb").set_trace()``
Rendering cache:
----------------
``t-cache="key_cache"`` tags part of template to be cached at rendering time.
Every sub-directives will be call only during the first rendering. It means
that the sql queries excecuted during the rendering of those sub-directives
are also done only once.
``t-nocache="documentation"`` tags part of template to be render every time.
The content can only use the root values.
Why and when to use ``t-cache``?
''''''''''''''''''''''''''''''''
This directive is used to speed up the rendering, by caching parts of the final
document, which may save queries to the database. However, it should be used
sparingly, as ``t-cache`` will inevitably complicate templates (and their
understanding of ``t-set`` for example).
However, in order to actually save database queries, it might be necessary to
render the template with values that are evaluated lazily. If those lazy
values are used in a cached part, they will not be evaluated if the part is
available in cache.
The ``t-cache`` directive is useful for template parts using values that depend
on a limited amount of data. We recommend to analyze the rendering of the
template with the profiler (by activating the "**Add qweb directive context**"
option). Passing lazy values to the rendering in controllers allow you to
display the directives using these values and triggering the queries.
A concern of using such a cache are making it available to different users
(different users should render the cached parts the same way). Another
potential issue is to invalidate its entries when necessary. For the latter,
the **key expression** should be chosen wisely. Using the ``write_date`` of a
recordset can make a cache key out-of-date without having to discard it
explicitly from the cache, for instance.
One should also pay attention to the fact that the values in ``t-cache`` parts
are scoped. This implies that if there are ``t-set`` directives in this part of
the template, the rendering of what comes after it could be different than if
there was no ``t-cache`` directive.
What if there is a ``t-cache`` inside a ``t-cache``?
''''''''''''''''''''''''''''''''''''''''''''''''''''
The parts are cached. Each containing only the string corresponding to its
rendering. Thus, the ``t-cache`` inside will probably be read less often, its
cache key will not necessarily be used. If this must be the case, then you may
need to add a ``t-nocache`` (on the same node or a parent).
What is ``t-nocache`` used for?
'''''''''''''''''''''''''''''''
If you want to cache part of a template with ``t-cache`` but a small piece must
remain dynamic and be evaluated at cache times. However, the part in
``t-nocache`` will not have access to the ``t-set`` value of the template. Only
the values provided by the controller are accessible there.
For example, the menu is cached because it's the same all the time and takes
time to render (using the performance devtools with the qweb context lets you
investigate). However, in the menu, we want the ecommerce cart to be always up
to date. So there is a ``t-nocache`` to keep this part dynamic.
The base of ``t-cache``
'''''''''''''''''''''''
The ``t-cache`` directive allows you to store the rendered result of a template.
The **key expression** (eg 42: ``t-cache="42"``) will be evaluated as a python
expression. This will be used to generate the **cache key**. So there can be
different **cache values** (cached render part) for the same template part. If
the **key expression** is a tuple or a list, it will be searched when generating
the **cache key**. If one or more recordsets are returned by the **key
expression**, then the model, ids and their corresponding write_date will be
used to generate the **cache key**. Special case: If the **key expression**
returns a Falsy value, then the content will not be cached.
Example::
<div t-cache="record,bool(condition)">
<span t-if="condition" t-field="record.partner_id.name">
<span t-else="" t-field="record.partner_id" t-options-widget="contact">
</div>
In this case, there may be values (string) in the cache corresponding to each
record already returned with a true condition, as well as for the false
condition. And if a module modifies the record, the write_date being modified,
the cached value is discarded.
``t-cache`` and scoped values (``t-set``, ``t-foreach``...)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Values in ``t-cache`` are scoped, this involves a change in behavior between
having or not having ``t-cache`` on one of the parent nodes. Don't forget to
take into account that Odoo uses a lot of templates, ``t-call`` and view
inheritance. Adding a ``t-cache`` can therefore modify the rendering of a
template that you do not see when editing.
(``t-foreach`` it's like a ``t-set`` for each iteration)
Example::
<div>
<t t-set="a" t-value="1"/>
<inside>
<t t-set="a" t-value="2"/>
<t t-out="a"/>
</inside>
<outside t-out="a"/>
<t t-set="b" t-value="1"/>
<inside t-cache="True">
<t t-set="b" t-value="2"/>
<t t-out="b"/>
</inside>
<outside t-out="b"/>
</div>
Will render::
<div>
<inside>2</inside>
<outside>2</inside>
<inside>2</inside>
<outside>1</inside>
</div>
The base of ``t-nocache``
'''''''''''''''''''''''''
The template part contained in a node with a ``t-nocache`` attribute is not
cached. This content is therefore **dynamic** and is rendered systematically.
However the available values are those provided by the controller (when
calling the ``_render`` method).
Example::
<section>
<article t-cache="record">
<title><t t-out="record.name"/> <i t-nocache="">(views: <t t-out="counter"/>)</i></titlle>
<content t-out="record.description"/>
</article>
</section>
Will render (counter = 1)::
<section>
<article>
<title>The record name <i>(views: 1)</i></titlle>
<content>Record description</content>
</article>
</section>
Here the ``<i>`` tag that contains the container will always be rendered. While
the rest is as a single string in the cache.
``t-nocache`` and scoped root values (``t-set``, ``t-foreach``...)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The contents of the ``t-nocache`` tag can be used for documentation and to
explain why the directive is added.
The values are scoped into ``t-nocache``, these values are root values only
(values provided by the controller and/or when calling the ``_render`` method
of ``ir.qweb``). ``t-set`` can be done in the template part, but will not be
available elsewhere.
Example::
<section>
<t t-set="counter" t-value="counter * 10"/>
<header t-nocache="">
<t t-set="counter" t-value="counter + 5"/>
(views: <t t-out="counter"/>)
</header>
<article t-cache="record">
<title><t t-out="record.name"/> <i t-nocache="">(views: <t t-out="counter"/>)</i></titlle>
<content t-out="record.description"/>
</article>
<footer>(views: <t t-out="counter"/>)</footer>
</section>
Will render (counter = 1)::
<section>
<header>
(views: 6)
</header>
<article>
<title>The record name <i>(views: 1)</i></titlle>
<content>Record description</content>
</article>
<footer>(views: 10)</footer>
</section>
Here the ``<i>`` tag that contains the container will always be rendered. While
the rest is as a single string in the cache. The counter is not updated by the
``t-set`` out of the ``t-nocache``
``t-nocache-*`` add some primitive values in the cache
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
In order to be able to use values generated in the template, it is possible to
cache them. The directive is used as ``t-nocache-*="expr"`` where ``*`` is the
name of the chosen value and ``expr`` the python expression so the result will
be cached. The cached value must be primitive type.
Example::
<section t-cache="records">
<article t-foreach="records" t-as="record">
<header>
<title t-field="record.get_method_title()"/>
</header>
<footer t-nocache="This part has a dynamic counter and must be rendered all the time."
t-nocache-cached_value="record.get_base_counter()">
<span t-out="counter + cached_value"/>
</footer>
</article>
</section>
The value ``cached_value`` is cached with the cached template part of
``t-cache="records"`` and add to the scoped root values each time.
Helpers Helpers
------- -------
@ -514,15 +736,20 @@ be returned from the controller (or further customized to suit).
View-based View-based
'''''''''' ''''''''''
At a deeper level than the previous helper is the ``render`` method on At a deeper level than the previous helper is the ``_render`` method on
``ir.ui.view``: ``ir.qweb`` (use the datable) and the public module method ``render``
(don't use the database):
.. py:method:: render(cr, uid, id[, values][, engine='ir.qweb][, context]) .. py:method:: _render(id[, values])
Renders a QWeb view/template by database id or :term:`external id`. Renders a QWeb view/template by database id or :term:`external id`.
Templates are automatically loaded from ``ir.ui.view`` records. Templates are automatically loaded from ``ir.qweb`` records.
Sets up a number of default values in the rendering context: ``_prepare_environment`` method sets up a number of default values in
the rendering context. The ``http_routing`` and ``website`` addons,
also default values they need.
You can use ``minimal_qcontext=False`` option to avoid this default
value like the public method ``render``:
``request`` ``request``
the current :class:`~odoo.http.Request` object, if any the current :class:`~odoo.http.Request` object, if any
@ -546,6 +773,11 @@ At a deeper level than the previous helper is the ``render`` method on
used to expand or customize QWeb locally (by creating used to expand or customize QWeb locally (by creating
a "new" qweb based on ``ir.qweb`` with alterations) a "new" qweb based on ``ir.qweb`` with alterations)
.. py:method:: render(template_name, values, load, **options)
:func:`load(ref)`
returns etree object, ref
.. _reference/qweb/javascript: .. _reference/qweb/javascript:
.. todo:: the members below are no longer relevant, section to rewrite .. todo:: the members below are no longer relevant, section to rewrite