A key idea in web development is URL routing. It describes how particular URLs are mapped to matching handlers or functions inside a web application. The system decides which function should process the request and produce a response when a user navigates to a URL. This is crucial for organizing web applications' flow and making sure that various pages or functionality are reachable via intuitive URLs. The back-end logic may be arranged correctly thanks to URL routing, which guarantees that requests are routed to the appropriate processing handlers.
Since Odoo's routing controls how web pages, forms, and APIs are accessible, developers who wish to create or expand the platform's functionality must understand how it operates. The Controller in Odoo's Model-View-Controller (MVC) architecture is in charge of managing web requests. In addition to processing requests and returning replies (HTML, JSON, etc.), the controller communicates with the model and view layers. In order to offer different pages or data when a given URL is reached, routes specify the paths or URLs that map to these controller methods.
Controllers and HTTP Requests
A controller in Odoo is a Python class that manages web requests and serves as a conduit between the server-side logic and the user's browser. Incoming HTTP requests must be processed by controllers, who must then communicate with the business logic (models) and provide the proper answers.
The @http.route decorator is the main mechanism used to route HTTP requests to controllers. By mapping particular URLs to controller methods, this decorator enables the developer to specify how the application should behave when a user accesses particular URLs. Based on the URL, this routing mechanism makes sure that the appropriate controller and method handle incoming requests.
Odoo controllers can handle different HTTP methods, including:
- GET: Frequently used to load pages, this function retrieves resources.
- POST: Usually used to send data to the server, such as when filling out a form.
- PUT: For updating existing resources.
- DELETE: To delete a resource.
By mapping these HTTP methods to specific routes, Odoo enables flexible web request handling.
Odoo’s @http.route Decorator
The basis of Odoo's URL routing is the @http.route decorator. It enables developers to specify which patterns in URLs will cause particular controller methods to be called. The fundamental syntax is:
@http.route('/url_path', type='http', auth='public', methods=['GET'])
def controller_method(self, **kwargs):
return 'Response content'
- '/url_path': Specifies the URL to match.
- type='http': Indicates that the route will return an HTTP response. You can also use type='json' to indicate that the method returns JSON data.
- auth='public': Defines the authentication level required to access the route. Other values include user (logged-in users) and none (no authentication required).
- methods=['GET']: Specifies which HTTP methods are allowed (e.g., GET, POST, etc.).
Developers can define multiple routes within a single controller by adding multiple @http.route decorators for different URL patterns or request methods.
Example of a Simple Route
Here’s a simple example that demonstrate how to map a URL to a controller method and return an HTML response:
from odoo import http
class MyController(http.Controller):
@http.route('/hello', type='http', auth='public', methods=['GET'])
def hello_world(self, **kwargs):
return '<h1>Hello, World!</h1>'
- When accessed through a web browser, the route '/hello' will invoke the hello_world method.
- "Hello, World!" appears on the website as the method's straightforward HTML answer.
Similarly, you can handle JSON responses:
@http.route('/api/data', type='json', auth='public', methods=['POST'])
def return_json(self, **kwargs):
data = {'key': 'value'}
return data
When reached using a POST request, this route produces JSON data, which is helpful for API endpoints or AJAX calls.
Advanced Routing Techniques
Routes in Odoo may have dynamic segments that let you extract variables straight from the URL. The controller method can accept these segments as parameters.
Syntax: By putting placeholders in angle brackets (< >) in the URL, you can build dynamic segments. For instance, captures a string, whereas catches an integer.
@http.route('/product/<int:id>', type='http', auth='public', website=True)
def product(self, id):
return "Product ID: %s" % id
- This route will match URLs like /product/5 and pass 5 as the id argument to the product method.
- Validation and Parsing: Odoo uses the placeholder to automatically verify the parameter type (such as string or integer). Odoo will produce a 404 error if the captured value is not of the intended type.
Multiple Routes in One Decorator
Using a list of URLs in the @http.route decorator, Odoo enables the definition of various URL patterns for the same procedure. When you wish to supply many URLs that initiate the same logic, this functionality is helpful.
Syntax: A list of strings can be supplied to define several routes
@http.route(['/shop', '/store'], type='http', auth='public', website=True)
def shop(self):
return "Welcome to the shop!"
- In this case, both /shop and /store will trigger the shop method.
- Use Cases: In order to manage legacy URLs, provide user-friendly URLs, or support various naming conventions (such as /cart and /basket leading to the same endpoint), this method is frequently employed.
Working with Query Strings
You may retrieve query string parameters from the URL (the part that comes after the? ) in Odoo. You can change your controller's behavior with these settings without changing the route pattern.
Query Parameter Access: The request.params dictionary provides access to query parameters.
@http.route('/search', type='http', auth='public')
def search(self):
query = request.params.get('q')
return "Search results for: %s" % query
- If the URL is /search?q=Odoo, the method will capture Odoo as the value of query and return the corresponding search results.
- Pitfalls and Best Practices:
- To prevent problems like SQL injection or processing improper data, always verify the query parameters.
- Give default settings or deal with situations in which the query parameters are absent.
Route Prioritization / Order of Evaluation
Odoo uses the order in which routes are registered to choose which route to execute when several routes match a request. More specialized routes are usually given precedence over more general ones.
Order of Definition: Which route is used in the event of a conflict depends on the order in which your code defines the routes.
@http.route('/item/<int:id>', type='http', auth='public')
def item_by_id(self, id):
return "Item with ID %s" % id
@http.route('/item/<string:name>', type='http', auth='public')
def item_by_name(self, name):
return "Item with name %s" % name
If you request /item/123, Odoo will prioritize the first route (/item/<int:id>) since the URL matches an integer. If the URL contains a string, it will fall back to the second route (/item/<string:name>).
Practical Examples
A basic illustration of how to create an Odoo route that returns HTML or text. When understanding URL routing, this is frequently the initial step.
from odoo import http
class HelloWorld(http.Controller):
@http.route('/hello', auth='public', methods=['GET'])
def hello(self):
return "Hello, world!"
Explanation: The route /hello is mapped to the hello method in the HelloWorld controller. When accessed via a GET request, it returns a basic "Hello, world!" message as plain text.
Endpoint: "Hello, world!" will appear in the browser when you visit http://localhost:8069/hello.
Form Submission
Creating a form, submitting data, and processing it in a controller is a common web functionality. This example shows how to create a form and handle its data in Odoo.
class FormController(http.Controller):
@http.route('/form', auth='public', methods=['GET'])
def form(self, **kw):
return """
<form action="/form/submit" method="post">
<input type="text" name="name" placeholder="Your name" required>
<input type="submit" value="Submit">
</form>
"""
@http.route('/form/submit', auth='public', methods=['POST'])
def form_submit(self, **kw):
name = kw.get('name', '')
return f"Hello, {name}!"
Explanation: The first route (/form) renders an HTML form that accepts a name. When the form is submitted via POST, the form_submit method captures the input data and returns a personalized greeting.
Endpoint: The form can be viewed by going to http://localhost:8069/form. You will be taken to a page that greets you with the name you entered after submitting the form.
JSON Endpoint
Returning JSON data is useful for AJAX calls and APIs. This example shows how to create a JSON response for use in web apps.
class JsonController(http.Controller):
@http.route('/json_data', auth='public', methods=['GET'], type='json')
def json_data(self):
return {'message': 'This is a JSON response', 'status': 'success'}
Explanation: The /json_data route returns a JSON response. By setting type='json' in the decorator, Odoo automatically serializes the return value into JSON format. This is useful for API endpoints or AJAX calls that expect JSON data.
Endpoint: The JSON answer that appears when you visit http://localhost:8069/json_data is as follows:
{
"message": "This is a JSON response",
"status": "success"
}
Dynamic Content Rendering
Odoo uses the QWeb templating engine for rendering dynamic content. You can pass data to templates and render views from a route.
class TemplateController(http.Controller):
@http.route('/template', auth='public', methods=['GET'])
def template(self, **kw):
values = {'title': 'Welcome to Odoo', 'content': 'This is a dynamic page.'}
return http.request.render('my_module.template_view', values)
Explanation: The template route renders a view using the QWeb template engine. The http.request.render() method is used to render the template_view view, passing a dictionary of values (title and content) to the template.
Endpoint: The given values will dynamically fill the template as Odoo renders the content using the template_view QWeb template when a user accesses http://localhost:8069/template.
Testing and Debugging Routes
The steps below will help you test and debug your routes effectively, ensuring that your Odoo application is functioning as expected.
Using Odoo’s Built-In Logging
For troubleshooting and verifying that routes are appropriately mapped and accessible in Odoo, logging is a crucial tool. To monitor route accesses and other important operations, you can enable logging in Odoo.
Turning on logging: The Python logging package can be used to provide logging for your routes. An example of how to log incoming requests to a route is provided here:
import logging
from odoo import http
_logger = logging.getLogger(__name__)
class MyController(http.Controller):
@http.route('/log_example', auth='public', methods=['GET'])
def log_example(self, **kw):
_logger.info("Route /log_example was accessed.")
return "For more information, see the log."
Log Levels
Numerous log levels, including DEBUG, INFO, WARNING, ERROR, and CRITICAL, are supported by Odoo. Utilize these levels in accordance with the message's seriousness.
- DEBUG is for fine-grained informational events.
- INFO provides general information about the route being accessed.
- WARNING for potentially harmful situations.
- ERROR for errors and issues.
- CRITICAL for severe errors.
Tips for Debugging
Always log significant actions, such as the beginning and end of requests, especially for POST requests.
Look for any unexpected behavior or route-related errors in Odoo's logs, which are typically found in the logs directory of your Odoo installation.
Inspecting Route Definitions
You can check the registered routes in Odoo to see if your route is accurately defined or being accessed.
Examining Routes: Using Odoo's internal tools, you can view a list of every registered route.
from odoo import http
class RouteInspector(http.Controller):
@http.route('/inspect_routes', auth='public')
def inspect_routes(self):
routes = http.request.env['ir.http'].search([])
for route in routes:
print(route.url)
return "Routes have been printed to the console."
Command-Line or Interactive Debugging: To run your Odoo instance in debug mode and view logs and interactions right in the console, use the odoo-bin command:
- Run Odoo in debug mode: ./odoo-bin --dev=all
- The --dev=all flag enables detailed logging and error reports, helping you see all route information and request handling in the logs.
Interactive Debugging with PDB: Python's built-in debugger, pdb, may also be used to step through the code and examine variables in real time when Odoo is running in a development environment.
Unit Testing Controllers
Your controllers and routes will function as intended thanks to unit testing. You can use the testing framework that Odoo offers to create tests for your unique controllers and routes.
Writing Unit Tests: Odoo's testing infrastructure integrates the unittest module.
from odoo.tests import TransactionCase
class TestMyController(TransactionCase):
def test_hello_world_route(self):
response = self.env['ir.http'].web_request('/hello')
self.assertEqual(response, "Hello, world!")
Test Setup: To ensure that your production data is not impacted, Odoo's test framework creates a test database and conducts the tests in a separate environment.
Running Tests: You can run tests from the command line using the odoo-bin utility:
./odoo-bin --test-enable --db-filter=my_database_name
Recommended Practices
- To make sure your routes handle a range of edge cases, provide tests for both valid and invalid inputs.
- To confirm that the response corresponds to the anticipated output, use the assertEqual function.
- To guarantee that every component of functionality is verified separately, isolate tests to certain routes and controllers.