DEV Community

Guewen Baconnier
Guewen Baconnier

Posted on • Updated on

Using a domain stored in a field for a Many2one

It is a very common pattern in Odoo to filter available records in a Many2one depending on another field.

For instance, users can select a Stock Location only if it abides by some rules. You may have a computed field, that gives the allowed locations for a move line.

The issue

Let's take a fictive use case where we allow moving a product in a location only if this location is associated to this product.

In Python:


class StockMoveLine(models.Model):
    _inherit = "stock.move.line"

    allowed_location_ids = fields.Many2many(
        comodel_name="stock.location",
        compute="_compute_allowed_location_ids"
    )

    @api.depends("product_id", "move_id.location_dest_id")
    def _compute_allowed_location_ids(self):
        for line in self:
            destination = line.move_id.location_dest_id
            line.allowed_location_ids = destination.allowed_sublocations(line.product_id)

Enter fullscreen mode Exit fullscreen mode

And in the XML view:

<field name="allowed_location_ids" invisible="1" />
<field name="location_dest_id" domain="[('id', 'in', allowed_location_ids)]"/>
Enter fullscreen mode Exit fullscreen mode

It works quite well, until you have a large number of locations, e.g. 5000 allowed locations. When you change the product, an onchange is triggered to get the new allowed_location_ids, which is done very fast server_side, but the front-end starts to freeze (5-10 seconds).

Image of browser freezing with "a web page is slowing down your browser" message

This issue happens because we return 5000 ids to a Many2many widget, which has to process every single id.

ℹ️ I encountered this issue in Odoo 13.0, it may or may not still happen on newer versions.

The solution

Here comes to the rescue the OCA module web_domain_field.

As stated in its description:

In order to mitigate these limitations this new addon allows you to use the value of a field as domain of another field in the xml definition of your view.

Go read the description of the module as it gives other interesting use cases.

Using a domain set directly in the field short-circuits the Many2many widget on the view and fixes the performance issue.

Our code would now look like:

In Python:


class StockMoveLine(models.Model):
    _inherit = "stock.move.line"

    allowed_location_domain = fields.Char(
        compute="_compute_allowed_location_domain"
    )

    @api.depends("product_id", "move_id.location_dest_id")
    def _compute_allowed_location_domain(self):
        for line in self:
            destination = line.move_id.location_dest_id
            allowed_locations = destination.allowed_sublocations(line.product_id)
            line.allowed_location_domain = json.dumps([("id", "in", allowed_locations.ids)])

Enter fullscreen mode Exit fullscreen mode

And in the XML view:

<field name="allowed_location_domain" invisible="1" />
<field name="location_dest_id" domain="allowed_location_domain"/>
Enter fullscreen mode Exit fullscreen mode

The real use case used to showcase this Odoo module was in stock_storage_type.

Top comments (2)

Collapse
 
martinvarela85 profile image
Martin Varela

Great addon! Solved us a lot of performance issues.

The domain field shouldn't be fields.Char?

Collapse
 
guewen profile image
Guewen Baconnier

Oh, yes of course! Thanks for the correction :)