Django's New Database Constraints

Sep 03, 2019
hackajob Staff

In April 2019, Django released version 2.2. Offering long term support, this new version marks the end of mainstream support for Django 2.1. This new version comes with several updates that are aimed at making things easier for those who work with Django. Whilst we're all waiting for Django 3 (it’s believed to be the first integration of asynchronous web requests after all), the new features in version 2.2 are worth checking out.

One of these new features is the introduction of database constraints. Previously, some of the constraint checks introduced in Django 2.2 could be achieved by overriding the save method at the model. Whilst some opt to enforce these as validations at the view level; this is relatively ineffective because any other code that accesses the model directly will not become validated.

As an example, let’s say you enforce a view validation that ensures the age of the user is above eighteen years. This will work until you create another view (let’s say for an admin to create users) which doesn’t include this validation. In our opinion, database-level constraints offer better enforcement of business logic such as this.

To demonstrate the use of the new constraints feature in Django 2.2, we’re going to theorise creating a model named ‘Employee’. This model will have the following fields:

Name

Email

Age

Department

Supervisor

Is_Active

Is_Available

We recommend creating a different model with different fields when practising this tutorial, as it will help you to improve your understanding of the concepts shared here.

Below, Figure 1 demonstrates the code for this model:

Figure 1

The Unique Constraint

Let’s begin with a relatively easy check; ensuring two or more fields are unique. This check was previously implemented using ‘unique_together’, as shown below:

The above implementation is pretty direct and we need the ‘name’ and ‘email’ fields to be unique together. For example, if an employee’s name is ‘John Doe’ and their email is ‘john_doe@email.com’, another employee cannot be registered with the same exact email and name. However, a notice has come with the release of Django 2.2 stating that ‘unique_together’ will soon be deprecated and replaced by ‘UniqueConstraint’.

Implement the same check as above with the new feature (‘UniqueConstraint’). The recent database constraints are still implemented in the Meta class, yet a key difference is that they are defined under the variable name ‘constraints’. This contains an iterable of all the checks placed on a model. In this case, we have the UniqueConstraint method that is derived from the model class.

This method takes two arguments: ‘fields’ and ‘name’. The ‘fields’ parameter expects a list of the fields you’d like to be unique together, which is similar to how this constraint was implemented before. The ‘name’ argument is your chosen identifier for this constraint. With this check in place, if you try to create an employee with the same email and name as another user, you’ll get the following error:

The Check Constraint

This constraint ensures that given rules are met before a new model object is created. Similar to ‘UniqueConstraint’, this is a method in the models’ class. The method takes two arguments: ‘check’ and ‘name’. ‘Name’ is similar to that in the ‘UniqueConstraint’, whilst ‘check’ states the constraint that you’d like enforced.

In this case, the ‘check’ is to ensure that you don’t register underage employees (e.g. below 18 years of age). If you try and do this, you could create an employee with an age of 16 years. The database constraint that you introduce won’t allow this and instead, the following error will be raised: ‘ValidationError’:

These constraints introduced in Django 2.2 a relief for developers who always wanted to implement validations at the model level. There is so much you can do with them in your web development, so be creative and get cracking.