My goal is to turn the standard website URL of a Product:
/shop/product/ipad-retina-display-5
into a different format:
/shop/product/5/ipad/ipad-с-дисплеем-retina/a2323
where ID is moved to right after the `/shop/product/`, brand follows ID, Internal Reference is added to the end of the URL, and most importantly the product name is translated to the language currently selected (in this example - Russian).
I use the following code to achieve all but translations:
class my_module_website_sale(website_sale):
@http.route(['/shop/product/<product_model:product>'])
def product(self, product, category='', search='', **kwargs):
return super(my_module_website_sale, self).product(product, category=category, search=search, **kwargs)
and this:
from openerp.addons.website.models import website
from openerp.addons.website.models.ir_http import RequestUID
from openerp.addons.website.models.website import slugify
old_slug = website.slug
def slug_product(value):
if isinstance(value, tuple):
id, brand, name, default_code = value
else:
id, brand, name, default_code = value.id, value.product_variant_ids[0].brand_id.name, value.name, value.default_code
return '%s/%s/%s/%s' % (id, brand, slugify(name), default_code)
def slug(value):
if isinstance(value, browse_record) and value._name == 'product.template':
return slug_product(value)
return old_slug(value)
website.slug = slug
class ProductModelConverter(werkzeug.routing.PathConverter):
def __init__(self, url_map):
super(ProductModelConverter, self).__init__(url_map)
self.regex = '([0-9]+)/.*'
def to_python(self, value):
m = re.match(self.regex, value)
_uid = RequestUID(value=value, match=m, converter=self)
return request.registry['product.template'].browse(
request.cr, _uid, int(m.group(1)), context=request.context)
def to_url(self, value):
return slug_product(value)
def generate(self, cr, uid, query=None, args=None, context=None):
brands = {b['id']: b['name'] for b in fetchdictall(cr, 'SELECT id, name FROM my_module_brand')}
products = [(tmpl, brands.get(brand, ''), name, code)
for (tmpl, brand, name, code) in
fetchall(cr, 'SELECT product_tmpl_id, brand_id, name_template, default_code FROM product_product '
'LEFT JOIN product_template t ON product_tmpl_id = t.id WHERE t.website_published = true ORDER BY product_tmpl_id')]
templates_done = set()
for product in products:
if product[0] not in templates_done:
templates_done.add(product[0])
yield {'loc': product}
class ir_http(models.AbstractModel):
_inherit = 'ir.http'
def _get_converters(self):
return dict(super(ir_http, self)._get_converters(), product_model=ProductModelConverter)
This code works perfectly well for the ASCII URLs, e.g. this URL brings me to the required website shop page:
/shop/product/5/ipad/ipad-retina-display/a2323
However, once translated to Russian, this URL raises an error on the werkzeug level (i.e. not even reaching my code, AFAIU):
/shop/product/5/ipad/ipad-с-дисплеем-retina/a2323
The error:
2016-08-09 05:15:26,210 3902 INFO mgr werkzeug: 127.0.0.1 - - [09/Aug/2016 05:15:26] "GET /ru_RU/shop/product/5/ipad/%D0%B2%D0%BE%D0%B4%D1%8F%D0%BD%D0%BE%D0%B9-%D1%88%D0%BB%D0%B0%D0%BD%D0%B3/a2323 HTTP/1.0" 500 -
2016-08-09 05:15:26,217 3902 ERROR mgr werkzeug: Error on request:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 177, in run_wsgi
execute(self.server.app)
File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 165, in execute
application_iter = app(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/service/server.py", line 291, in app
return self.app(e, s)
File "/home/a0c/programs/openerp/odoo/openerp/service/wsgi_server.py", line 224, in application
return application_unproxied(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/service/wsgi_server.py", line 210, in application_unproxied
result = handler(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/http.py", line 1292, in __call__
return self.dispatch(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/http.py", line 1266, in __call__
return self.app(environ, start_wrapped)
File "/usr/lib/python2.7/dist-packages/werkzeug/wsgi.py", line 579, in __call__
return self.app(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/http.py", line 1266, in __call__
return self.app(environ, start_wrapped)
File "/usr/lib/python2.7/dist-packages/werkzeug/wsgi.py", line 579, in __call__
return self.app(environ, start_response)
File "/home/a0c/programs/openerp/odoo/openerp/http.py", line 1439, in dispatch
result = ir_http._dispatch()
File "/home/a0c/programs/openerp/odoo/addons/crm/ir_http.py", line 13, in _dispatch
response = super(ir_http, self)._dispatch()
File "/home/a0c/programs/openerp/odoo/addons/website/models/ir_http.py", line 145, in _dispatch
return self.reroute('/'.join(path) or '/')
File "/home/a0c/programs/openerp/odoo/addons/website/models/ir_http.py", line 166, in reroute
return self._dispatch()
File "/home/a0c/programs/openerp/odoo/addons/crm/ir_http.py", line 13, in _dispatch
response = super(ir_http, self)._dispatch()
File "/home/a0c/programs/openerp/odoo/addons/website/models/ir_http.py", line 72, in _dispatch
func, arguments = self._find_handler()
File "/home/a0c/programs/openerp/odoo/openerp/addons/base/ir/ir_http.py", line 65, in _find_handler
return self.routing_map().bind_to_environ(request.httprequest.environ).match(return_rule=return_rule)
File "/usr/lib/python2.7/dist-packages/werkzeug/routing.py", line 1202, in bind_to_environ
path_info = _get_wsgi_string('PATH_INFO')
File "/usr/lib/python2.7/dist-packages/werkzeug/routing.py", line 1199, in _get_wsgi_string
return wsgi_decoding_dance(val, self.charset)
File "/usr/lib/python2.7/dist-packages/werkzeug/_compat.py", line 92, in wsgi_decoding_dance
return s.decode(charset, errors)
File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 21-27: ordinal not in range(128)
Does anybody have an idea how to properly configure werkzeug's PathConverters (or I dunno what else) to make them accept non-ASCII URLs?
Many thanks!