Web pages and controllers
Odoo also provides a web development framework, which can be used to develop website features closely integrated with our backend apps. We will take our first steps toward this by creating a simple web page to display the list of pending To-Do Tasks. It will respond at a URL with the format http://my-server/todo, so /todo is the URL endpoint we want to implement.
We will just have a short taste of what web development with Odoo looks like, and this topic is addressed in more depth in Chapter 12, Creating Website Frontend Features.
Web controllers are the components responsible for web page rendering. Controllers are methods defined in a http.Controller class, and they are bound to URL endpoints.
When that URL endpoint is accessed, the controller code executes, producing the HTML to be presented to the user. To help with rendering the HTML, we have the QWeb templating engine available.
The convention is to place the code for controllers inside a /controllers subdirectory. First, edit the todo_app/__init__.py so that it also imports the controllers module directory:
from . import models
from . import controllers
We then need to add a todo_app/controllers/__init__.py file so that the directory can be Python imported, and add an import statement to it for the Python file we will add:
from . import main
Now add the actual file for the controller, todo_app/controllers/main.py, with the following code:
from odoo import http
class Todo(http.Controller):
@http.route('/todo')
def Main(self, **kwargs):
TodoTask = http.request.env['todo.task']
domain_todo = [('is_done', '=', False)]
tasks = TodoTask.search(domain_todo)
return http.request.render(
'todo_app.index_template', {'tasks': tasks})
The odoo.http module, imported here, is the core component providing web-related features. The http.Controller object is the class controller it should derive from. We use it for the main controller class.
The particular name we choose for the class and for their methods is not relevant. The @http.route decorator is the important part, since it declares the URL endpoint that will be bound to the class method, /todo in our case. By default, access to URL endpoints requires the user to be logged in. This can be changed, and anonymous access can be allowed by adding the auth='public' parameter to @http.route.
Inside the controller method, we access the environment using http.request.env. We use it to get a recordset with all not-done To-Do Tasks.
The final step is to use http.request.render() to process the todo_app.index_template QWeb template and generate the output HTML. We can make values available to the template through a dictionary. This is used to pass the tasks recordset.
If we try this now, we should get an error message in the server log:
ValueError: External ID not found in the system: todo_app.index_template
This is expected since we haven't defined that template yet. That should be our next step.
QWeb templates are a type of view, and should also go in the /views subdirectory. Let's create the views/index_template.xml file:
<?xml version="1.0" encoding="utf-8"?> <odoo>
<template id="index_template" name="My Todo List">
<div id="wrap" class="container">
<h1>Todo Tasks</h1>
<!-- List of Tasks -->
<t t-foreach="tasks" t-as="task">
<div class="row">
<span t-field="task.name" />
</div>
</t>
</div>
</template>
</odoo>
The <template> element is used to declare a QWeb template. In fact, it is a shortcut for a ir.ui.view record, and this is the base model where templates are stored. The template contains the HTML to use, and makes use of QWeb-specific attributes. t-foreach is used to loop through each item of the tasks variable, made available by the controller's http.request.render() call. The t-field takes care of properly rendering the content of a record field.
This is just a glimpse of the QWeb syntax. More details can be found in Chapter 12, Creating Website Frontend Features.
We still need to declare this file in the module manifest, like the other XML data files, so that it gets loaded and can be made available. After doing this and performing a module upgrade, our web page should be working. Open the http://<my-server>:8069/todo URL and you should see a simple list of To-Do Tasks.