Skip to main content

Model constraints

Model constraints

Often, applications need to ensure data integrity, and enforce some validations to ensure that data is complete and correct.

The PostgreSQL database manager supports many useful validations, such as avoiding duplicates, or checking that values meet certain simple conditions. Model can declare and use PostgreSQL constraints for this.
Some checks require more sophisticated logic, and are better implemented as Python code. For these cases, we can use specific model methods implementing Python constraint logic.

SQL model constraints

SQL constraints are added to the database table definition and are enforced directly by PostgreSQL. They are definedusing the _sql_constraints class attribute.
It is a list of tuples, and each tuple has the format (name, code, error):
  • name is the constraint identifier name
  • code is the PostgreSQL syntax for the constraint
  • error is the error message to present to users when the constraint is not verified
We will add two SQL constraints to the Book Model. One is a unique constraint ensuring that we don't have repeated books with the same title and publication date; the other is to check that the publication date is not in the future:
# class Book(models.Model): 
    _sql_constraints = [
        ('library_book_name_date_uq',  # Constraint unique identifier
         'UNIQUE (name, date_published)',  # Constraint SQL syntax
         'Book title and publication date must be unique.'),  # Message
        ('library_book_check_date',
         'CHECK (date_published <= current_date)',
         'Publication date must not be in the future.'),
    ]
For more information on the PostgreSQL constraint syntax, see the official documentation at https://www.postgresql.org/docs/10/static/ddl-constraints.html.

Python model constraints

Python constraints can use a piece of arbitrary code to check the conditions. The checking function should be decorated with @api.constrains and an indication of the list of fields involved in the check. The validation is triggered when any of them is modified and will raise an exception if the condition fails.

In the case of the Library app, an obvious example is to prevent inserting incorrect ISBN numbers. We already have the logic to check that an ISBN is correct, in the _check_isbn() method. We can use it now in a model constrain to prevent saving incorrect data:
from odoo.exceptions import ValidationError

# class Book(models.Model):
    @api.constrains('isbn')
    def _constrain_isbn_valid(self):
        for book in self:
            if book.isbn and not book._check_isbn():
                raise ValidationError(
                    '%s is an invalid ISBN' % book.isbn)

Comments

Popular posts from this blog

The message and activity features

The message and activity features Odoo has available global  messaging  and activity planning features, provided by the  Discuss  application, with technical name mail. The mail module provides the  mail.thread  abstract class that makes it simple to add the messaging features to any model, and the  mail.activity.mixin  that adds planned activity features. This was done in  Chapter 4 ,  Extending Modules , to explain how to inherit features from mixin abstract classes. To add these features, we need to add the mail dependency to the add-on module,  library_checkout , and then have the library checkout model class inherit from the abstract classes providing the following features. Edit the  'depends'  key in the  library_checkout/__manifest__.py   file, to add the mail module, shown as follows: Copy 'depends': ['library_member' , 'mail' ], And edit the  library_checkout/m...

Setting up an nginx reverse proxy

Setting up an nginx reverse proxy While Odoo itself can serve web pages, it's strongly recommended that there is a  reverse  proxy positioned in front of it. A reverse proxy acts as an intermediary that manages the traffic between clients sending requests and the Odoo servers responding to them. Using a reverse proxy has several benefits. On the security side, it can do the following: Handle (and enforce) HTTPS protocols to encrypt traffic Hide the internal network characteristics Act as an application firewall, limiting the URLs accepted for processing Also, on the performance side, it can provide the following significant improvements: Cached static content, hence reducing the load on the Odoo servers Compressed content to speed up loading time Act as a load balancer, distributing load between several servers Apache is a popular choice when considering a reverse proxy, although  nginx  is a recent alternative with good technical argumen...

The QWeb template language

The QWeb template language The  QWeb  parser looks for special directives in the templates and replaces them with dynamically generated HTML. These directives are XML element attributes and can be used in any valid tag or element, such as  <div> ,  <span> , or  <field> . Sometimes, we may want to use a QWeb directive but we don't want to place it in any of the XML elements in our template. For those cases, we have a  <t>  special element that can have QWeb directives, such as  t-if  or  t-foreach , but is silent and won't have any output on the final XML/HTML produced. The QWeb directives will frequently make use of evaluated expressions to produce different results, depending on the current record values. There are two different QWeb implementations: client-side JavaScript and server-side Python. The reports and website pages use the server-side Python implementation of QWeb. Kanban views us...