Django Models Part 4 (Model validation, Model Meta, Abstract Model class)

Search for a command to run...

No comments yet. Be the first to comment.
This series will cover the core concepts on web application development using Django, from basic installation to user authentications and some core concepts. Status: 9/14 published ✅
Django under the hood provides an app called Admin a.k.a Django Admin, which provides Admin UI interface/web page for your Django Project. This admin interface can automatically generate CRUD views/ (form/tables) for your models with very minimal set...
Nothing serious, just experimenting on Django Framework

Working with simple media uploads and serving these media files

Using static files like JavaScript, CSS, images with Django

Class() based views in Django

function() based views in Django

To validate a model field on application level we can create up a validator which is a callable that take the value to be validated and raises error (ValidationError to be precise) if the value doesn't meet the criteria or it is invalid
The ValidationError it raises can be imported as from django.core.exceptions import ValidationError
We can add callable validators to our model field through validators arguments
Let's take a simple example of a model having a field email which requires @djangotherightway.com emails to be valid
from django.core.exceptions import ValidationError
from django.db import models
def django_the_right_way_email_validator(email):
if not email.endswith('@djangotherightway.com'):
raise ValidationError('Email must end with @djangotherightway.com')
class Info(models.Model):
email = models.EmailField(
validators=[django_the_right_way_email_validator]
)
You can add as many validator function/callables to a field
Sometime we come up for a need to validate two or more field together or are dependent on each other, in such scenario we can use clean() method provided by models.Model
Let's add up simple requirements on our previous model example. Let's add up phone_number and age to our model, and imagine a situation where phone_number is required if age>20
from django.core.exceptions import ValidationError
from django.db import models
def django_the_right_way_email(email):
if not email.endswith('@djangotherightway.com'):
raise ValidationError('Email must end with @djangotherightway.com')
class Info(models.Model):
email = models.EmailField(
validators=[django_the_right_way_email]
)
# make phone nullable, since phone_number is
# required only if age>20
phone_number = models.CharField(
max_length=10, null=True, blank=True
)
age = models.IntegerField()
def clean(self):
if self.age > 20:
if not self.phone_number:
raise ValidationError(
'Phone number is required if age is greater than 20'
)
These validators we created will not run automatically when you create/update object/row. To make this validators run, we need to call full_clean() method which under the hood runs all the validator
Note: Validators run automatically when using
ModelForm
# this code can be on your view func or ...
# ...for this example you can use django shell
# Open Django shell using: python manage.py shell
obj = Info()
obj.email = "example@djangotherightway.com"
obj.age = 21
obj.phone_number = '1234567890'
try:
obj.full_clean()
except ValidationError as e:
print(e)
else:
obj.save()
Have a look into full_clean() Django code:Github where it runs all individual field validators like
django_the_right_way_emailin our case and even runsclean()method we implemented for validationsYou can call
full_clean()from your modelssave()method, so that you don't have to manually callfull_clean()everytime while validating objects, but this might bring up another issue offull_clean()being called two times in case usingModelForm.
Django already has a collection of validators used for general purpose that we can use openly as a function/callable validator to our Model field or Forms or you own data validation
These built-in validators can be imported from django.core.validators module
Some list of commonly used built-in validators are validate_email, validate_slug, validate_ipv4_address, validate_ipv6_address, int_list_validator, validate_image_file_extension e.t.c
A simple example to demonstrate use of built-in validators
from django.db import models
from django.core.validators import validate_email
class Info(models.Model):
# we didn't make email=models.EmailField()
# because models.EmailField() would already contain
# validate_email validator that checks for
# valid email addresses
email = models.CharField(validators=[validate_email])
Model Meta class in Django is a way to provide some more information regarding table_name whether model is abstract singular or plural names app_label ordering and many more....
Python metaclass is different than that of Django model meta class. Metaclass in Python are class factory where as meta class in Django is completely different which is used to provide additional information about a model to Django. Don't get confused on they sharing the same name during our
pronouncingspeakinglisteningbut they are way different on writings.
Meta options class in DjangoDjango automatically create a database table for every models in the format of {app_name}_{model_name}, so lets customize this behaviour and provide it with a custom table name
from django.db import models
class Address(models.Model):
name = models.CharField(max_length=100)
class Meta:
db_table = 'address'
Now, when we create migrations file and run our migrations through migrate command, django will create a table named address instead of its default {app_name}_address
abstract=True this model will be a abstract model classdb_table is set to a value, Django will take this value to create database table like we saw in previous examplemanaged=True (default behaviour) Django will create and manage database table for this modelmanaged=False table is not created. This might be useful to integrate already existing table into DjangoAbstract model base class is also a model class which is used to place common model fields used in other models into a single model so that it can be used/inherited into other model.
Database Table by the migrations frameworkInformation abstract base classfrom django.db import models
class InfoBase(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
class Meta:
abstract = True
class User(InfoBase):
address = models.CharField(max_length=100)
So, the User model will now have fields name email address, where name and email is inherited from the InfoBase abstract model class
Override fields in child model
Some time, we may need to override some fields from the base class so that it gets changed in our child class. let's take an example we need to change max_length of name in User, we can do it by
class User(InfoBase):
name = models.CharField(max_length=50) # changed
address = models.CharField(max_length=100)
Remove/delete fields in child model
Some time, there may occur a case when we need to delete/remove some fields in our child class, we can do it by simply overriding the fields with None value
class User(InfoBase):
name = models.CharField(max_length=50)
email = None
address = models.CharField(max_length=100)
So, considering this example, User model will only have name and address fields