Creating or modifying templates - QWeb

We'll add website capabilities to the library addon developed in Chapter 4, Application models, and following. What we're interested in is allowing users to browse through the library and, if they are logged in with the appropriate permissions, enable them to edit book content right from the website interface.

Getting ready

As we make use of the library.book model, get chapter 4's code for my_module. For convenience, this recipe's code contains a copy of it.

How to do it...

We'll need to define a couple of controllers and views:

  1. Add a template that displays a list of books in views/library_book_templates.xml.
    <odoo>
      <template id="books">
        <t t-call="website.layout">
            <section>
                This is an editable text before the list of books.
            </section>
            <t t-foreach="books" t-as="book">
                <article itemscope="itemscope"
                         itemtype="http://schema.org/Book"
                         t-attf-class="row book-#{book_parity}">
                    <h2 t-field="book.name" class="col-md-12" />
                    <t t-if="book.date_release">
                        <div class="col-md-2"
                             t-att-dateCreated="book.date_release"
                             t-field="book.date_release" />
                    </t>
                    <ul  class="col-md-10">
                        <li t-foreach="book.author_ids" t-as="author" itemprop="author">
                            <t t-esc="author.name" />
                        </li>
                    </ul>
                </article>
            </t>
            <section contenteditable="False">
                This is a non-editable text after the list of books.
            </section>
        </t>
      </template>
    </odoo>
  2. Add a controller that serves the list of books in controllers/main.py.:
    @http.route('/books', type='http', auth="user", website=True)
    def route(self):
        return request.render(
            'ch13_r02.books',
            {
                'books': request.env['library.book'].search([]),
            })

With this code in place, users can query existing books and see their details. Given appropriate permissions, users will also be offered to change book details and a couple of other texts.

How it works...

First, we create a template called books that is used to generate the HTML necessary to display a list of books. All of the code is wrapped in a t element with the t-call attribute set, which makes Odoo render the website.layout template and insert our content at the place the called template has designated for it. This way, we get a full Odoo web page with the menu, footer, and so on, without having to repeat any code. If you leave out this call, you'll have to generate this or similar code yourself.

Loops

For working on record sets, you need a construct to loop through lists. Have a look at the inside of the t-call element, where the actual content generation happens. The template expects to be rendered with a context that has a variable called books set and iterates through it in the t-foreach element. Iteration can happen in a t element, in which case its contents are repeated for every member of the iterable that was passed in the t-foreach attribute. You can also place a t-foreach and t-as attribute in some arbitrary element; then this element and its contents will be repeated for every item in the iterable. The t-as attribute is mandatory and will be used as the name of the iterator variable to use for accessing the iterated data. While the most common use for this construction is to iterate over record sets, you can use it on any Python object that is iterable.

Attributes

We use as many of the semantic HTML5 elements as possible, which is why the actual data is wrapped in an article tag. For machine readability, some item* properties are attached. You can read more about this in this recipe's See also section.

Now focus on the t-attf-class attribute here. This will be evaluated by QWeb to be the attribute class with the contents evaluated as a format string. That is, the string row book- is passed as it is and the contents of the #{...} snippet is evaluated as Python code. This is different from t-att-dateCreated (note the missing 'f', the first is an attribute format string, the latter an evaluation) used below, where the whole content is evaluated as Python code. Both forms just pass the part of their name after the second dash as the name of the attribute to be constructed.

It is pretty much up to you when to choose a t-attf-* construction and when to use t-att-*, the rule of thumb is to use a format string if the result contains a lot of string literals anyway and an evaluation otherwise.

Fields

The h2 and div tags that follow use the t-field attribute. This attribute needs to be passed a field within a record set with length one and transparently allows the user to change the content displayed when the website's edit mode is activated. Of course, this is subject to a permission check and only allowed if the current user has write permissions on the displayed record. With an optional t-field-options attribute, you can give a dictionary of options to be passed to the field renderer, including the widget to be used. Currently, there's no vast amount of widgets for the backend, so the choices are a bit limited here.

Conditionals

Note that the division showing the publication date is wrapped by a t element with the t-if attribute set. This attribute is evaluated as Python code and the element only rendered if the result is truthy . In the example, we only show the div class if there is actually a publication date set.

Note

Note that t-if doesn't coexist well with other templating attributes like t-esc or t-field on the same element. Put each of them in its own element, because, otherwise, the t-if usually wins and the other attributes are not evaluated any more.

Inline editing

Changes made by a user will either be propagated to the connected database record if the change happened within a t-field node, or to the view in question if it is some other node marked as editable. Content nodes like section elements don't need to be marked as editable, they are editable by default. To turn an editable element read-only, use the attribute contenteditable=False.

Note

Note that editing a view via the website editor sets the noupdate flag on this view. This means that subsequent code changes will never make it into your customer's database. In order to also get the ease of use of inline editing and the possibility of updating your HTML code in subsequent releases, create one view that contains the semantic HTML elements and a second one that injects editable elements. Then only the latter view will be noupdate and you can still change the former.

For the CSS classes used here, consult bootstrap's documentation, as linked in this recipe's See also section.

The controller in step 2 just renders the template, please refer to the Chapter 13, Web Server Development, recipe Modify an existing handler for details.

There's more...

Given the way t-call elements are evaluated, you can use t-set elements to pass information to the template you call. This can be very useful if you have some generalized templates like website.layout or report.external_layout, which display data you want to see almost always. Adapt them not to print certain elements if some variable is set and set it via a t-set element on the page or report where you want to suppress the element in question. This helps to avoid a lot of code duplication.

Within t-foreach loops, you've got access to a couple of variables whose names are derived from the accompanying t-as attribute. As it is book in the example above, we have access to the variable book_parity which contains the value even for even indices while iterating and odd for odd ones. In this example, we use this to be able to have alternating background colors in our list. Other interesting variables in this case would be book_index, which returns the current (zero-based) index in the iteration, book_first and book_last, which are True if this is the first or last iteration respectively, and book_value, which would contain the item's value if the book variable we iterate over were a dictionary; in this case, book would iterate through the dictionary's keys.

The template element is a shorthand for a record element that sets some properties on the record for you. While there's never a reason not to use the convenience of the template element, you should know what happens under the hood: the element creates a record of the model ir.ui.view with type qweb. Then, depending on the template element's name and inherit_id attributes, the inherit_id field on the view record will be set. In case the template has the attribute primary set to True, the view record's mode field will be set to primary. Finally, an arch field is crafted with the correct root element (t for non-inheriting views, data for inheriting views) and a t-name attribute is set for primary views.

Keep in mind that QWeb is a perfectly generic templating engine, so whenever you need to generate content in an Odoo context, use a Qweb view that you render by calling env['ir.ui.view'].render('xmlid', parameters). Especially for generating XML documents, this is convenient, but you can generate every other kind of text too.

See also

For a more in-depth discussion of controllers, see the Chapter 13, Web Server Development, recipes Make a path accessible from the network and Restrict access to web accessible paths.

For details on view inheritance, see the Chapter 8, Backend Views, recipe Changing existing views: View inheritance.

The code generated here makes use of microdata (https://html.spec.whatwg.org/multipage/microdata.html) using definitions from http://schema.org – it is advised you do the same for your publicly accessible websites in order to simplify reading your pages for machines. This also makes your content more accessible for search engines.

Odoo as a whole makes extensive use of bootstrap (http://getbootstrap.com), which you should use to get adaptive designs without much effort.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset