Skip to main content

Extending web controllers and templates

Extending web controllers and templates

Extensibility is something we expect in all features of Odoo, and web features are no exception, so existing controllers and templates can be extended.
As an example, we will extend our Book catalogue web page to leverage the book availability information we just added:
  • On the Controller side, we will add support to a query string parameter, to filter only the available books: /library/books?available=1
  • On the Template side, we will add an indication on the books that are not available

Extending Web Controllers

Web Controllers should not have actual business logic, and focus on presentation logic. We might want to add support for additional URL parameters or even routes, which are used to change the presentation of the web page.
We will extend the /library/books endpoint to support a query string parameter, available=1, filtering the catalogue of book to only the available titles.
To extend an existing Controller, we need to import the corresponding Object, and then implement the method with the additional logic.


Let's add a new library_member/controllers/main.py file with the following code:
from odoo import http 
from odoo.addons.library_app.controllers.main import Books
 
class BooksExtended(Books):
    @http.route()
    def list(self, **kwargs):
        response = super().list(**kwargs)
        if kwargs.get('available'):
            Book = http.request.env['library.book']
            books = Book.search([('is_available', '=', True)])
            response.qcontext['books'] = books
        return response
The controller to extend, Books,  was defined in the library_app/controllers/main.py file. Therefore, we will import it from odoo.addons.library_app.controllers.main. This is different from Models, where we use a central registry, which is accessible through the env object, to reference any Model class, without knowing the particular file implementing it. With controllers, we don't have that, and we need to know the module and file implementing the controller to extend.
We then declare a class, BooksExtended, based on the original one, Books. The identifier name used for this class is not relevant. We just use it to inherit and extend the methods defined in the original class.
Next, we (re)define the controller method to be extended, list(). It needs to be decorated with at least the simple @http.route() for its route to be kept active. If used like this, with no arguments, it will preserve the routes defined by the parent class. But we could also add parameters to this @http.route() decorator so that we can redefine and replace the class routes.
In the extended hello() method, we start by using  super() to run the existing code. This returns a Response object  resulting from that processing. The Response has attributes with the template to render, template, and the context to use when rendering, qcontext. But the HTML is yet to be generated. That will only happen when the controller finishes running. This gives us the opportunity to change the Response attributes before the final rendering is done.
The list() method has a **kwargs argument, capturing all parameters given into a kwargs dictionary. These are the parameters given in the URL, such as ?available=1. The method checks the kwargs for an available key with a value, and if so, changes the qcontext to have a books recordset with only the available books.

We should not forget to make this new Python file known to our module. We can do this by adding the controllers subdirectory to the library_member/__init__.py file:
from . import models
from . import controllers
And the library_member/controllers/__init__.py  file with this line of code:
from . import main 
After this, accessing http://localhost:8069/library/books?available=1 should show us only the books with the Is Available? field checked.

Extending QWeb Templates

To modify the actual presentation of the web page, we need to extend the QWeb template being used.
We will be extending the library_app.book_list_template to show additional information on the books that are not available.
Add the library_member/views/book_list_template.xml file by using the following code:
<odoo>
  <template id="book_list_extended"
            name="Extended Book List"
            inherit_id="library_app.book_list_template">

    <xpath expr="//span[@t-field='book.publisher_id']" position="after">
      <t t-if="not book.is_available">
        <b>(Not Available)</b>
      </t>
    </xpath>

  </template>
</odoo>
Web page templates are XML documents, just like the other Odoo View types, and we can use xpath to locate elements and then manipulate them, just like we could with the other View types. The inherited template is identified in the <template> element by the inherit_id attribute.

Note

In the preceding example, we used the more versatile xpath notation, but in this case, we could have used the equivalent simplified notation: <span t-field="book.publisher_id" position=after>.
We should not forget to declare this additional data file in our add-on manifest, library_member/__manifest__.py:
'data': [
    'views/book_view.xml',
    'security/library_security.xml',
    'security/ir.model.access.csv',
    'views/member_view.xml',
    'views/library_menu.xml',
    'views/book_list_template.xml',
],
After this, accessing http://localhost:8069/library/books should show the additional (Not Available) information on the books that are not available.

Comments

Popular posts from this blog

The message and activity features

The message and activity features Odoo has available global  messaging  and activity planning features, provided by the  Discuss  application, with technical name mail. The mail module provides the  mail.thread  abstract class that makes it simple to add the messaging features to any model, and the  mail.activity.mixin  that adds planned activity features. This was done in  Chapter 4 ,  Extending Modules , to explain how to inherit features from mixin abstract classes. To add these features, we need to add the mail dependency to the add-on module,  library_checkout , and then have the library checkout model class inherit from the abstract classes providing the following features. Edit the  'depends'  key in the  library_checkout/__manifest__.py   file, to add the mail module, shown as follows: Copy 'depends': ['library_member' , 'mail' ], And edit the  library_checkout/m...

Setting up an nginx reverse proxy

Setting up an nginx reverse proxy While Odoo itself can serve web pages, it's strongly recommended that there is a  reverse  proxy positioned in front of it. A reverse proxy acts as an intermediary that manages the traffic between clients sending requests and the Odoo servers responding to them. Using a reverse proxy has several benefits. On the security side, it can do the following: Handle (and enforce) HTTPS protocols to encrypt traffic Hide the internal network characteristics Act as an application firewall, limiting the URLs accepted for processing Also, on the performance side, it can provide the following significant improvements: Cached static content, hence reducing the load on the Odoo servers Compressed content to speed up loading time Act as a load balancer, distributing load between several servers Apache is a popular choice when considering a reverse proxy, although  nginx  is a recent alternative with good technical argumen...

The QWeb template language

The QWeb template language The  QWeb  parser looks for special directives in the templates and replaces them with dynamically generated HTML. These directives are XML element attributes and can be used in any valid tag or element, such as  <div> ,  <span> , or  <field> . Sometimes, we may want to use a QWeb directive but we don't want to place it in any of the XML elements in our template. For those cases, we have a  <t>  special element that can have QWeb directives, such as  t-if  or  t-foreach , but is silent and won't have any output on the final XML/HTML produced. The QWeb directives will frequently make use of evaluated expressions to produce different results, depending on the current record values. There are two different QWeb implementations: client-side JavaScript and server-side Python. The reports and website pages use the server-side Python implementation of QWeb. Kanban views us...