Skip to content

Creating Routes with Slug Parameters in Odoo Website: A Complete Guide

Odoo slug parameters

Are you looking to create custom routes in Odoo Website that can handle model records as parameters using the slug function? In this comprehensive tutorial, I’ll walk you through the process of creating routes in Odoo Website that use model records as parameters. This powerful technique allows you to build SEO-friendly URLs and create more intuitive navigation paths for your Odoo applications.

Why Use Slug Parameters in Odoo Routes?

When developing custom websites with Odoo, you often need to create routes that link to specific model records. For instance, you might want to display a product category page with a URL like /category/office-supplies instead of /category/42. Using the slug function provides several important benefits:

  1. SEO-friendly URLs: Search engines prefer descriptive URLs over ones filled with numbers and IDs.
  2. Improved user experience: Users can better understand where a link will take them.
  3. More memorable links: Text-based URLs are easier to remember than numeric IDs.
  4. Maintainable code: Your routes become more meaningful to developers maintaining the code.

Let’s dive into how to implement this in your Odoo website.

Understanding the Basics: Routes in Odoo Website

Before we get into creating routes with slug parameters, let’s first understand how basic routes work in Odoo.

In Odoo’s website module, routes are defined using Python decorators. The most common decorator is @http.route(), which allows you to specify:

  • The URL pattern
  • The HTTP methods allowed (GET, POST, etc.)
  • Authentication requirements
  • And more

Here’s a simple example of a basic route:

@http.route('/my-route', type='http', auth='public', website=True)
def my_route_function(self):
    return request.render('module_name.template_id')

This creates a route at /my-route that renders a specific template when accessed.

Getting Started with Slug Parameters

In our previous example, we saw how to create routes with specific parameters. Now, let’s explore how to use model records as parameters using the slug function.

What is the Slug Function?

The slug() function in Odoo converts a record name and ID into a URL-friendly string. For example, if you have a product category named “Office Supplies” with ID 42, slug(category) might return something like office-supplies-42.

Setting Up Our Project

First, let’s create a route that accepts a model record as a parameter. We’ll build on the example from the context:

@http.route('/category/<model("product.category"):category>', type='http', auth='public', website=True)
def product_category(self, category):
    # Display information about the category
    print("ID:", category.id)
    print("Name:", category.name)
    return request.render('module_name.product_category_template', {
        'category': category
    })

In this route, <model("product.category"):category> tells Odoo to:

  1. Look for a product.category record
  2. That matches the slug provided in the URL
  3. And pass it to our function as the category parameter

Handling Permissions for Public Access

One common issue when creating routes with model parameters is access rights. If you’re creating a public-facing website, you need to ensure that public users have read access to the models you’re using in your routes.

Adding Access Rights

To fix permission issues, you need to grant read access to the specific model for public users. In our example, we need to ensure public users can read product.category records.

Create or modify a security CSV file in your module:

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_product_category_public,product.category.public,model_product_category,base.group_public,1,0,0,0

This grants read-only access (perm_read=1) to the public user group for the product.category model.

Handling Errors Gracefully

Another important aspect to consider is error handling. What happens if a user tries to access a category that doesn’t exist? By default, Odoo will return a 500 error, which is not user-friendly.

Let’s modify our approach to handle errors more gracefully by extending the slug function behavior. We’ll create a custom implementation that redirects to a 404 page instead of showing a 500 error when a record doesn’t exist.

Create a new file named custom_slug.py in your module:

from odoo import models
from odoo.http import request
from odoo.addons.http_routing.models.ir_http import slug as original_slug

class CustomSlug(models.AbstractModel):
    _inherit = 'ir.http'
    
    def slug(self, record):
        try:
            return original_slug(record)
        except ValueError:
            # Log the error for debugging
            print("Custom error in slug method with record:", record)
            # Return empty string to trigger a 404 redirect
            return ""

Then, update your module’s __init__.py to import this file.

Creating Links to Our Custom Routes

Now that we have our route set up, let’s create links that use it. In your templates, you can create links using the slug function:

<a t-att-href="'/category/' + slug(category)">
    <t t-esc="category.name"/>
</a>

This will generate a link like /category/office-supplies-42 that, when clicked, will route to our product_category function with the appropriate category loaded.

Building a Complete Example

Let’s put everything together in a complete example. We’ll create a module with:

  1. Custom routes for viewing product categories
  2. Templates for displaying category information
  3. Proper security settings
  4. Error handling for invalid slugs

Module Structure

my_module/
├── __init__.py
├── __manifest__.py
├── controllers/
│   ├── __init__.py
│   └── main.py
├── models/
│   ├── __init__.py
│   └── custom_slug.py
├── security/
│   └── ir.model.access.csv
└── views/
    └── templates.xml

Main Controller (controllers/main.py)

from odoo import http
from odoo.http import request
from odoo.addons.http_routing.models.ir_http import slug

class CategoryController(http.Controller):
    
    @http.route('/categories', type='http', auth='public', website=True)
    def categories_list(self):
        # Display a list of all categories
        categories = request.env['product.category'].sudo().search([])
        return request.render('my_module.categories_list_template', {
            'categories': categories
        })
    
    @http.route('/category/<model("product.category"):category>', type='http', auth='public', website=True)
    def product_category(self, category):
        # Display information about the specific category
        print("ID:", category.id)
        print("Name:", category.name)
        return request.render('my_module.product_category_template', {
            'category': category
        })

Templates (views/templates.xml)

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <!-- Template for listing all categories -->
    <template id="categories_list_template" name="Categories List">
        <t t-call="website.layout">
            <div class="container">
                <h1>Product Categories</h1>
                <div class="row">
                    <div class="col-md-12">
                        <ul class="list-group">
                            <t t-foreach="categories" t-as="category">
                                <li class="list-group-item">
                                    <a t-att-href="'/category/' + slug(category)">
                                        <t t-esc="category.name"/>
                                    </a>
                                </li>
                            </t>
                        </ul>
                    </div>
                </div>
            </div>
        </t>
    </template>
    
    <!-- Template for displaying a specific category -->
    <template id="product_category_template" name="Product Category">
        <t t-call="website.layout">
            <div class="container">
                <h1><t t-esc="category.name"/></h1>
                <div class="row">
                    <div class="col-md-12">
                        <p>Category ID: <t t-esc="category.id"/></p>
                        <h2>Products in this category</h2>
                        <ul class="list-group">
                            <t t-foreach="category.product_tmpl_ids" t-as="product">
                                <li class="list-group-item">
                                    <t t-esc="product.name"/>
                                </li>
                            </t>
                        </ul>
                    </div>
                </div>
            </div>
        </t>
    </template>
</odoo>

Security Settings (security/ir.model.access.csv)

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_product_category_public,product.category.public,product.model_product_category,base.group_public,1,0,0,0

Advanced Techniques for Slug Parameters

Now that we’ve covered the basics, let’s explore some advanced techniques for working with slug parameters in Odoo.

Multiple Parameters in Routes

You can combine multiple parameters in your routes, including both model records and primitive types:

@http.route('/category/<model("product.category"):category>/page/<int:page>', type='http', auth='public', website=True)
def product_category_paged(self, category, page=1):
    # Paginated display of products in a category
    products_per_page = 10
    products = request.env['product.template'].sudo().search([
        ('categ_id', '=', category.id)
    ], limit=products_per_page, offset=(page-1)*products_per_page)
    
    total_products = request.env['product.template'].sudo().search_count([
        ('categ_id', '=', category.id)
    ])
    
    total_pages = (total_products + products_per_page - 1) // products_per_page
    
    return request.render('my_module.product_category_paged_template', {
        'category': category,
        'products': products,
        'page': page,
        'total_pages': total_pages
    })

Nested Model Relationships

Sometimes you need to navigate through related models in your routes. For example, you might want to display all products of a specific category and brand:

@http.route('/category/<model("product.category"):category>/brand/<model("res.partner"):brand>', type='http', auth='public', website=True)
def category_brand_products(self, category, brand):
    products = request.env['product.template'].sudo().search([
        ('categ_id', '=', category.id),
        ('manufacturer', '=', brand.id)
    ])
    
    return request.render('my_module.category_brand_products_template', {
        'category': category,
        'brand': brand,
        'products': products
    })

Using Slugs for SEO Optimization

The slug function is not just for routing; it’s a powerful tool for SEO optimization. You can use it to generate SEO-friendly URLs for your content.

For example, if you’re building a blog module, you might use slugs to create URLs like /blog/how-to-optimize-your-odoo-website instead of /blog/post/42.

@http.route('/blog/<model("blog.post"):post>', type='http', auth='public', website=True)
def blog_post(self, post):
    return request.render('my_module.blog_post_template', {
        'post': post
    })

Troubleshooting Common Issues

When working with slug parameters in Odoo routes, you might encounter some common issues. Let’s address them:

500 Server Error

If you get a 500 server error when accessing your route, it could be due to:

  1. Access rights issues: Ensure public users have read access to the model.
  2. Non-existent record: The slug might be referring to a record that doesn’t exist.
  3. Custom errors in the template: Check your template for possible errors.

Our custom slug implementation helps handle the non-existent record issue by redirecting to a 404 page.

Performance Considerations

When using model parameters in routes, be mindful of performance implications:

  1. Database queries: Each route access will query the database to fetch the record.
  2. Cache utilization: Consider using Odoo’s caching mechanisms for frequently accessed routes.
  3. Security checks: Odoo performs access rights checks for each record, which adds overhead.

URL Conflicts

Be careful with route patterns to avoid conflicts. For example, if you have:

@http.route('/category/<string:name>', type='http', auth='public', website=True)
def category_by_name(self, name):
    # ...

@http.route('/category/<model("product.category"):category>', type='http', auth='public', website=True)
def product_category(self, category):
    # ...

Odoo might have trouble distinguishing between these routes. Always design your URL structure carefully to avoid conflicts.

Best Practices for Odoo Website Routes

Let’s wrap up with some best practices for creating and managing routes in Odoo websites:

1. Consistent URL Structure

Maintain a consistent URL structure across your website. For example:

  • /model/record-slug for individual records
  • /model/record-slug/related-model for related records
  • /model/record-slug/action for actions on records

2. Proper Security Management

Always consider who should have access to your routes:

  • Use auth='public' only when the route should be accessible to everyone
  • Use auth='user' when authentication is required
  • Set up proper record rules and access rights

3. Error Handling

Implement proper error handling to provide a good user experience:

  • Redirect to a 404 page for non-existent records
  • Provide clear error messages
  • Log errors for debugging purposes

4. Caching Considerations

For high-traffic websites, consider implementing caching:

@http.route('/category/<model("product.category"):category>', type='http', auth='public', website=True, website_published=True)
def product_category(self, category):
    # Add cache headers for browsers
    response = request.render('my_module.product_category_template', {
        'category': category
    })
    response.headers['Cache-Control'] = 'public, max-age=300'
    return response

5. URL Canonicalization

Ensure that each resource has a single canonical URL to avoid SEO penalties:

@http.route([
    '/category/<model("product.category"):category>',
    '/categories/<model("product.category"):category>',  # Alternative URL
], type='http', auth='public', website=True)
def product_category(self, category):
    # Redirect alternative URLs to the canonical one
    if request.httprequest.path.startswith('/categories/'):
        return request.redirect('/category/' + slug(category), 301)
    
    return request.render('my_module.product_category_template', {
        'category': category
    })

Conclusion: Leveraging the Power of Slug Parameters in Odoo Routes

In this comprehensive guide, we’ve explored how to create routes in Odoo that use the slug function to work with model records as parameters. By implementing these techniques, you can create more user-friendly and SEO-optimized URLs for your Odoo website.

We’ve covered everything from basic route definition to advanced techniques like custom slug handling, multiple parameters, and nested relationships. We’ve also addressed common issues and provided best practices for route management in Odoo.

By mastering these concepts, you’ll be able to create more sophisticated and user-friendly web applications with Odoo. Remember that well-designed URLs not only help with SEO but also improve the overall user experience of your website.

For more information about Odoo website development, check out the official Odoo documentation or explore the Odoo Community Association resources.

What route will you build next with your new slug parameter skills? The possibilities are endless!


Discover more from teguhteja.id

Subscribe to get the latest posts sent to your email.

1 thought on “Creating Routes with Slug Parameters in Odoo Website: A Complete Guide”

  1. Pingback: Awesome Odoo AI Website Copy: 5 Steps

Leave a Reply

WP Twitter Auto Publish Powered By : XYZScripts.com