Odoo is opensource and has module structure. So, for the question

– Is it possible to change /this/ in Odoo?

the only answer is:

– Yes, everything is possible to do in Odoo.

OK, but how to do that? Where to find an instruction of how to implement some particular feature?

Let's take an example. Imagine we need a custom link for product at website shop. By default link is generated from Name field, but you need to make it be generated from new Name SEO field.

i.e. instead of this link:


there should be this one:


where product has fields:

Name: iPad Mini

Name SEO: Super SEO link for iPad Mini

How to do that? Can we find the answer in documentation? I believe, it doesn't have an answer.

So, let's try to do it ourself. We have Odoo source, so let's try to find a solution there.

In our example we can start from seaching by /shop/product/:

./addons/website_sale_options/controllers/main.py:10:    @http.route(['/shop/product/<model("product.template"):product>'], type='http', auth="public", website=True)
./addons/website_sale/models/product.py:112:            res[product.id] = "/shop/product/%s" % (product.id,)
./addons/website_sale/models/product.py:186:            res[product.id] = "/shop/product/%s" % (product.product_tmpl_id.id,)
./addons/website_sale/controllers/main.py:230:    @http.route(['/shop/product/<model("product.template"):product>'], type='http', auth="public", website=True)
./addons/website_sale/controllers/main.py:276:    @http.route(['/shop/product/comment/<int:product_template_id>'], type='http', auth="public", methods=['POST'], website=True)
./addons/website_sale/controllers/main.py:850:        return request.redirect("/shop/product/%s?enable_editor=1" % slug(product.product_tmpl_id))

These lines from addons/website_sale/controllers/main.py looks interesting:

@http.route(['/shop/product/<model("product.template"):product>'], type='http', auth="public", website=True)
    def product(self, product, category='', search='', **kwargs):
What about <model("product.template"):product>? What is it? How it works? There should be a way for you to find the answer in source. Maybe you know about werkzeug library, maybe you know about slug function, maybe you know about ir.http model. So there should be a keyword to search. At the worst you can search by "model" keyword OR look through whole website module.

OK, I found the answer in addons/website/models/ir_http.py. Function to_url is what we need.

from openerp.addons.website.models.website import slug, url_for, _UNSLUG_RE


class ir_http(orm.AbstractModel):
    _inherit = 'ir.http'

    rerouting_limit = 10
    geo_ip_resolver = None

    def _get_converters(self):
        return dict(
            super(ir_http, self)._get_converters(),


class ModelConverter(ir.ir_http.ModelConverter):
    def __init__(self, url_map, model=False, domain='[]'):
        super(ModelConverter, self).__init__(url_map, model)
        self.domain = domain
        self.regex = _UNSLUG_RE.pattern

    def to_url(self, value):
        return slug(value)

where slug function is from addons/website/models/website.py
def slug(value):
    if isinstance(value, orm.browse_record):
        # [(id, name)] = value.name_get()
        id, name = value.id, value.display_name
        # assume name_search result tuple
        id, name = value
    slugname = slugify(name or '').strip().strip('-')
    if not slugname:
        return str(id)
    return "%s-%d" % (slugname, id)
So, that is. To make a custom link, we have to inherit ModelConverter and modify to_url function. Something like that:

from openerp.addons.website.models.website import slugify
from openerp.addons.website.models.ir_http import ModelConverter

class ModelConverterCustom(ModelConverter):
    def to_url(self, value):
        if isinstance(value, orm.browse_record) and hasattr(value, 'name_seo'):
            id, name = value.id, value.name_seo
            slugname = slugify(name or '').strip().strip('-')
            if slugname:
                return "%s-%d" % (slugname, id)
        return super(ModelConverterCustom, self).to_url(value)

class ir_http(orm.AbstractModel):
    _inherit = 'ir.http'

    def _get_converters(self):
        res = super(ir_http, self)._get_converters()
        res['model'] = ModelConverterCustom
        return res

This is the way I use in odoo development:

  • Dive into source
  • Figure out how it works
  • Create module to make changes you need