Constraints

In real-world Odoo development, we often need to control data integrity—making sure that users don’t enter invalid or conflicting data. Odoo offers some main tools for this:

  • SQL Constraints
  • Python Constraints

These are low-level constraints that work directly with the PostgreSQL database engine. They are fast and reliable, but not very flexible.

SQL Constraints

Syntax:


_sql_constraints = [
    (
        'constraint_name',
        'CHECK(sql_condition)',
        'Error message when condition is false'
    )
]

Example:


_sql_constraints = [
    (
        'date_order_required',
        "CHECK( (state IN ('sale', 'done') AND date_order IS NOT NULL) OR state NOT IN ('sale', 'done') )",
        "Confirmed sales orders must have a confirmation date."
    )
]

Here,The purpose of the SQL constraint, which was taken from the sale order, is to confirm that a confirmed sale order contains a confirmation date. If it doesn't work, an error message appears. Usually seen in the field declaration part, this Python-based SQL constraint is specified before to the coding section.

Python Constraints

You define a method and decorate it with @api.constrains. It automatically triggers when the specified fields are modified.


from odoo import models, fields, api, _
from odoo.exceptions import ValidationError

class YourModel(models.Model):
    _name = 'your.model'

    product_id = fields.Many2one('product.product', string='Product')

    @api.constrains('product_id')
    def check_product_is_not_kit(self):
        """Validation to check whether product is not a kit"""
        if self.env['mrp.bom'].search(
            ['|', ('product_id', 'in', self.product_id.ids), '&',
             ('product_id', '=', False),
             ('product_tmpl_id', 'in', self.product_id.product_tmpl_id.ids),
             ('type', '=', 'phantom')],
            count=True
        ):
            raise ValidationError(
                _("A product with a kit-type bill of materials cannot have a "
                  "reordering rule.")
            )

A product with a kit-type bill of materials is guaranteed to be devoid of any reordering rules by the warehouse's SQL constraint. An error message is displayed if this condition is broken.

Computed Fields

These are fields whose values are automatically calculated based on other fields. They’re useful for real-time computations like totals, discounts, or status flags.


from odoo import models, fields, api

class YourModel(models.Model):
    _name = 'your.model'

    amount = fields.Float(string='Amount')
    total = fields.Float(string='Total', compute='_compute_total')

    @api.depends('amount')
    def _compute_total(self):
        for rec in self:
            rec.total = rec.amount * 2

Computed fields are not saved in the database unless you explicitly ask Odoo to store them.


total = fields.Float(string='Total', compute='_compute_total', store=True)

When you use Odoo, computed fields are defined in the same way as normal fields, with the "compute" attribute naming the function that does the calculation. Computed fields are not searchable unless we explicitly configure them.

If you want users to edit the computed field and push the value back to the source field:


from odoo import models, fields, api

class YourModel(models.Model):
    _name = 'your.model'

    amount = fields.Float(string='Amount')
    total = fields.Float(string='Total', compute='_compute_total', inverse='_inverse_total')

    @api.depends('amount')
    def _compute_total(self):
        for rec in self:
            rec.total = rec.amount * 2

    def _inverse_total(self):
        for rec in self:
            rec.amount = rec.total / 2

Related Fields

In real-world business situations, there are times when we need to show the value of a field from another related model within the current model. In these cases, we use related fields by setting the related attribute to link and display the desired value.


from odoo import models, fields

class YourModel(models.Model):
    _name = 'your.model'

    partner_id = fields.Many2one('res.partner', string='Partner')
    partner_name = fields.Char(related='partner_id.name', string='Partner Name')

Reference Fields

Reference fields in Odoo are used to link any record from any model dynamically. Unlike Many2one, which links to a fixed model, a Reference field lets the user choose both the model and the record—making it perfect for scenarios where the linked object could be from multiple models.

In the user interface, the user first selects a model (e.g., Sale Order), after which a second dropdown appears to choose a specific record from that model; the field then internally stores both the model and the record ID as a tuple.

Syntax

In a reference field, the selection parameter is used to define the available models. You need to assign a list of tuples containing the model's technical name and its display name to this parameter.


from odoo import models, fields

class YourModel(models.Model):
    _name = 'your.model'

    reference = fields.Reference(
        selection=[('sale.order', 'Sale Order'), ('purchase.order', 'Purchase Order')],
        string="Document Reference"
    )

Or use a dynamic list


from odoo import models, fields, api

class YourModel(models.Model):
    _name = 'your.model'

    reference = fields.Reference(
        selection='get_model_list',
        string='Linked Document'
    )

    @api.model
    def get_model_list(self):
        models = self.env['ir.model'].search([])
        return [(model.model, model.name) for model in models]

The returned values should be in the form of a list.

whatsapp_icon
location

Calicut

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

location

Kochi

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

location

Bangalore

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

Send Us A Message