Constraints are the rules specified on a record that prevents incorrect data before saving the record. Odoo always ensures data integrity and enforces the validation processes to provide complete and correct data.
In Odoo 15, the constraints are set to the data using python and model constraints. These constraints are mainly intended to validate the data on the record before it is traced in the database. So let’s discuss the python and model constraints in Odoo 15.
SQL Constraints are defined on the model using the class attribute _sql_constaints. These constraints belong to the part of PostgreSQL. This attribute ‘_sql_constaints’ is assigned as the list of triples of strings. Its syntax is the following;
_sql_constraints = [(name, sql_def, message)]
Here the name is the constraint identifier name, sql_def is the PostgreSQL syntax of the constraint, and the message is the error message displayed to the user when the constraint or the condition is not satisfied.
For example,
_sql_constraints = [
('barcode_uniq', 'unique(barcode)', "A barcode can only be assigned to one product !"),
]
It’s a _sql_constraints taken from the model for products; it aims to verify that the barcode of each product is unique and, if it fails, then display the error message.
As per the syntax, the first string 'barcode_uniq' is the name of this constraint. This identifier name is followed by the SQL definition 'unique(barcode)'. UNIQUE constraint is the most used SQL constraint that prevents duplicating the data for the mentioned field. This unique constraint is provided with a field name whose duplicity is prevented. If the barcode is not unique, it will display the error message, the last list string for _sql_constraint.
This is how the error message will be displayed when the unique constraint identifies the duplicity of the data.
Another _sql_constraints is the CHECK constraint which checks the SQL expression on the data. For example,
_sql_constraints = [
('positive_qty', 'CHECK(qty > 0)', 'Contained Quantity should be positive.')
]
This is an example of using the CHECK constraints of the _sql_constraints. This constraint is mentioned in the model of Product Packaging. Here the constraints whose name is 'positive_qty' check if the quantity is greater than 0 or not. If it’s not greater than 0, then it will arise the error message.
An important note is that a python SQL constraint is defined before the coding section; it will always be specified in the field declaration section.
In some other cases, we may have to ensure data consistency by using more complex checks, so in that case, the python constraints are used. It’s a method decorated with constraints that are invoked on a record set.
A python constrains arbitrary codes to validate a record of data. Here the validation is performed by using a function that is decorated with the decorator ‘@api.constrains’.
@api.constrains('name', 'description')
def _check_description(self):
for record in self:
if record.name == record.description:
raise ValidationError("Fields name and description must be different")
This is the basic syntax that how we can use the python constraints. It consists of the decorator @api.constrains followed by the fields involved in the validation process. After this, the validation function is used for applying the conditions used for the check.
The validation function will be triggered whenever the validating fields are modified, and then it should raise an exception. Usually, the ‘ValidationError’ is used to show the exception. As the ‘_sql_constiants’ do, the python constraints also prevent saving the incorrect data to the database.
Here is an example that illustrates the python constraints;
@api.constrains('age')
def _check_something(self):
for record in self:
if record.age > 30:
raise ValidationError(“Age is greater than”)
In this example, the constraints specified to the field ‘age’ in a model check if the age is greater than 30 or not. If the validation fails, that means if the age is greater than 30, it will show the Validation error “Age is greater than,” and otherwise, it returns nothing.
We need to import ‘ValidationError’ or ‘UserError’ for showing an exception.
The @api.constrains only support simple fields( for example, partner_id.phone), and it will not support other related fields (for example, partner_id.customer), which will be ignored.
For @api.constrains, it has some other limitations; also, that is the @api.constrains will be triggered only if the field inside the constraints is included in the ‘create’ or ‘write’ functions it is because if the fields are not present in the view, it will not trigger the python functions.
Compared to python constraints, SQL constraints are more powerful and efficient. Even though it can be used as the needful, both will ensure data consistency.