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
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.
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
Post a Comment