• Thursday, January 1, 2026

Odoo 19 stands as a powerful and highly adaptable platform, designed to streamline the management and customization of diverse business applications. Its architecture empowers developers to effortlessly craft tailored solutions, addressing specific organizational needs, whether it involves sophisticated data management, process automation, or the development of unique workflows. A cornerstone of Odoo 19's flexibility is its web controller framework. This robust feature allows developers to construct bespoke front-end views and efficiently manage HTTP requests, serving as a critical bridge for integrating Odoo's backend with external applications or custom web pages. By leveraging web controllers, organizations can significantly extend Odoo's functionalities beyond standard ERP configurations, delivering responsive and engaging interactive experiences for their partners, suppliers, and customers.

In Odoo, controllers act as the essential bridge between the front-end website modules and the backend functionalities. They are instrumental in managing and configuring these front-end components, thereby facilitating the creation of a seamless and dynamic website experience. Controllers enable the definition of unique URLs, effectively linking your web pages directly to specific backend functions, ensuring a cohesive and interactive user journey.

To begin working with controllers in Odoo, the initial step involves establishing a dedicated controllers folder within your custom module. This folder will house all necessary Python files, including an __init__.py file, to properly organize your controller logic.

# -*- coding: utf-8 -*-
from . import controllers

Once this new controllers folder is established and initialized, it becomes an integral part of your module's structure, providing a dedicated and organized space for defining unique routes and enhancing Odoo's website capabilities.

Creating a Controller File

Creating a controller in Odoo provides the flexibility to establish unique web routes, enabling the retrieval of backend data and its seamless presentation on the front end. To achieve this, you will need to import the necessary modules and define your controller class within a designated controller file. For illustrative purposes, this example will demonstrate how to construct a controller that displays comprehensive sales order information.

# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
class SaleOrderController(http.Controller):
    @http.route(['/saleorders'], type="http", auth="user", website=True)
    def display_sale_orders(self, **kwargs):
        sale_orders = request.env['sale.order'].sudo().search(
            [], order="date_order desc"
        )
        return request.render(
            "custom_module_name.sale_order_website_custom_layout",
            {
                'orders': sale_orders
            }
        )

The @http.route decorator plays a pivotal role in Odoo when defining URL routes. It precisely specifies the mapping between a URL path and a particular controller function that will handle incoming requests. Below is a detailed explanation of its syntax and parameters:

Understanding the Route Decorator Parameters

  • '/saleorders': This parameter defines the specific URL path. When a user navigates to this URL (e.g., <your_domain>/saleorders), Odoo executes the associated function beneath this decorator to generate and display the corresponding webpage.
  • type='http': This option designates that the route is intended for standard HTTP requests, implying direct browser access. Alternatively, json is employed for API endpoints designed to deliver JSON-formatted data.
  • auth='user': This parameter dictates the level of authentication required for users to access the specified route. Key options include:
    • 'public': Allows access to anyone, including unauthenticated users.
    • 'user': Restricts access to authenticated, logged-in users only.
    • 'bearer': Employs token-based authentication, typically for API access, where an API token verifies the user.
    • 'none': Requires no authentication, making the route entirely open.
  • website: This boolean option indicates whether the controller is directly associated with the Odoo website. A value of True signifies a website-linked page, while False is used for non-website specific functionalities.
  • methods: If not explicitly defined, all HTTP methods are permitted by default. The primary methods include:
    • ['GET']: Utilized for retrieving information without modifying server-side data.
    • ['POST']: Employed for submitting data or initiating modifications on the server.
  • sitemap: This parameter facilitates the automatic generation of sitemap links, effectively serving as a directory of accessible pages and enhancing website navigation and discoverability.
  • cors: Cross-Origin Resource Sharing (CORS) is a mechanism that simplifies data exchange between servers and browsers, enabling secure cross-origin requests.
  • multilang: This functionality enables multi-language support for the front-end, allowing for the display of website content in various languages.
  • csrf: Cross-Site Request Forgery (CSRF) protection is provided by generating a unique token, thereby securing user sessions against malicious attacks.

At this point, the sale_orders variable holds all the retrieved sales order information. It's important to note that within controllers, request.env is the standard method for accessing the Odoo environment, while self.env is typically reserved for database interactions within Odoo models.

To prevent potential access permission issues when performing operations like searching or creating records, it is best practice to employ the sudo() method. This ensures that the system can retrieve or modify records without encountering authorization restrictions, granting necessary elevated privileges for the operation.

Following the retrieval of data, the request.render method is used to display the information by rendering a specified QWeb template. This method takes the template's XML ID and a dictionary of data to be passed to the template. Alternatively, if the goal is to navigate the user to a different URL instead of rendering a page, the request.redirect method can be utilized. For example, to redirect a user to the /shop page, the code would be:

 return request.redirect('/shop')

Creating the View Template

The next crucial step involves creating the sale_order_website_custom_layout XML template within your module's views folder. This template is essential as it is explicitly referenced by our controller, defining how the retrieved data will be structured and presented on the web page.

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <template id="sale_order_website_custom_layout" name="Sale Orders Custom Layout">
        <t t-call="website.layout">
            <div class="container mt-4">
                <h3>Sale Orders</h3>
                <table class="table table-bordered table-striped mt-3">
                    <thead>
                        <tr>
                            <th>Order</th>
                            <th>Date</th>
                            <th>Customer</th>
                            <th>Status</th>
                            <th class="text-end">Untaxed</th>
                            <th class="text-end">Tax</th>
                            <th class="text-end">Total</th>
                        </tr>
                    </thead>
                    <tbody>
                        <t t-foreach="orders" t-as="order">
                            <tr>
                                <td>
                                    <t t-esc="order.name"/>
                                </td>
                                <td>
                                    <t t-esc="order.date_order"/>
                                </td>
                                <td>
                                    <t t-esc="order.partner_id.name"/>
                                </td>
                                <td>
                                    <t t-esc="order.state"/>
                                </td>
                                <td class="text-end">
                                    <t t-esc="order.amount_untaxed"/>
                                </td>
                                <td class="text-end">
                                    <t t-esc="order.amount_tax"/>
                                </td>
                                <td class="text-end">
                                    <t t-esc="order.amount_total"/>
                                </td>
                            </tr>
                        </t>
                    </tbody>
                </table>
                <t t-if="not orders">
                    <div class="alert alert-info mt-3">
                        No sale orders found.
                    </div>
                </t>
            </div>
        </t>
    </template>
</odoo>

Upon successful implementation and navigation to the /saleorders page, all relevant sales orders will be dynamically displayed, as illustrated in the following image.

<img src="https://www.images.cybrosys.com/blog/Uploads/BlogImage/how-to-create-and-configure-web-controllers-in-odoo-19-1.png" alt="How to Create & Configure Web Controllers in Odoo 19-cybrosys" style="width:100%;" />

In conclusion, web controllers in Odoo 19 are indispensable tools that provide extensive capabilities for customizing web interactions. By meticulously defining routes, implementing sophisticated business logic, and efficiently managing responses, developers can craft truly unique and dynamic online experiences. These flexible tools empower businesses to extend Odoo's reach and provide tailored web solutions that meet specific user needs and business objectives.