Enable Dark Mode!
By: Ayana KP

How to Add Many2Many Fields in Odoo17 Website Form

Technical Odoo 17

Odoo 17 continues to be a powerful and versatile ERP system, and one of its standout features is the robust website builder. In this blog post, we'll explore how to enhance your Odoo 17 website forms by incorporating Many2Many fields. This dynamic feature allows you to establish complex relationships between records, providing an enriched experience for users interacting with your website.


We establish a custom model named custom_field. Simultaneously, we craft a controller and static file to introduce a JavaScript function, and we configure a view to accommodate XML files.

<?xml version="1.0" encoding="utf-8"?>
   <template id="many2many_odoo_blog"
       <xpath expr="//input[@name='vat']/.." position="after">
           <select class="js-example-basic-multiple col-xl-6 mb-1 new-get_data"
               <t t-foreach="tags" t-as="tag">
                   <option t-att-value="tag" t-esc="tag.name"/>

This illustration depicts the XML file that we're crafting as a template. We are inheriting the default website portal form view to integrate our custom-field tags. To accomplish this, specify the parent ID as model_name.template_id with the value "portal.portal_my_details_fields."

/** @odoo-module */
import publicWidget from "@web/legacy/js/public/public_widget";
var CustomForm = publicWidget.Widget.extend({
    selector: '.new-get_data',
    start: function () {
publicWidget.registry.Many2many_tag = CustomForm;
return CustomForm;

Include a JavaScript file and define its corresponding script. In this process, establish "module name.your_unique_name" and set a selector, "selector.new-get_data," for the select2() function to execute only when the user selects that specific selector.


Our Tags field is now visible in the customer portal form. Subsequently, to retrieve values from the backend, we import the Customer Portal, override the account function, and introduce our custom values.

from odoo.addons.portal.controllers.portal import CustomerPortal
from odoo.http import request, route
class CustomerPortal(CustomerPortal):
   def account(self, redirect=None, **post):
       res = super(CustomerPortal, self).account(self, **post)
       values = self._prepare_portal_layout_values()
       partner = request.env.user.partner_id
           'error': {},
           'error_message': [],
       if post and request.httprequest.method == 'POST':
           error, error_message = self.details_form_validate(post)
           values.update({'error': error, 'error_message': error_message})
           if not error:
               values = {key: post[key] for key in
                   {key: post[key] for key in self._get_optional_fields() if
                    key in post})
               for field in set(['country_id', 'state_id']) & set(
                       values[field] = int(values[field])
                       values[field] = False
               values.update({'zip': values.pop('zipcode', '')})
               self.on_account_update(values, partner)
               if redirect:
                   return request.redirect(redirect)
               return request.redirect('/my/home')
       countries = request.env['res.country'].sudo().search([])
       states = request.env['res.country.state'].sudo().search([])
       tags = request.env['crm.tag'].sudo().search([])
           'partner': partner,
           'countries': countries,
           'states': states,
           'tags': tags,
           'has_check_vat': hasattr(request.env['res.partner'], 'check_vat'),
           'partner_can_edit_vat': partner.can_edit_vat(),
           'redirect': redirect,
           'page_name': 'my_details',
       response = request.render("portal.portal_my_details", values)
       response.headers['X-Frame-Options'] = 'SAMEORIGIN'
       response.headers['Content-Security-Policy'] = "frame-ancestors 'self'"
       return response
       return res

The line tags = request.env['crm.tag'] initializes a variable named "tags" and assigns it the value obtained from crm.tag.search([]), which searches for all the tags within the "crm.tag" model.


We can now choose from all available "crm.tags" in our Many2Many field.

Adding Many2Many fields to Odoo 17 website forms opens up a world of possibilities for creating intricate relationships between records. Whether managing courses and students or any other related entities, this feature enhances the user experience and provides a more comprehensive solution for your business needs.

To read more about using group by for many2many fields in Odoo 16, refer to our blog How to Use Group by for Many2Many Fields in Odoo 16

If you need any assistance in odoo, we are online, please chat with us.


Leave a comment




Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635



Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.



Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message