How to design good Django models?

/ #Django


Designing good Django models is very important when it comes to readability and to maintainability. In this post I'll share some good tips on how to implement some good techniques.

A Django model example

from django.db import models

class Car(models.Model):
    brand = models.CharField(max_length=40)
    doors = models.IntegerField(default=5)
    color = models.CharField(max_length=30)

It's important and a good practice to use singular name on your models. Use Car and not Cars, this is because the model represent a single object of the Car and not all the cars in your database. It's also important to notice that the model definition is a class and then we use CamelCase to name them. Examples: Car, CarCompany. The attributes are named with snake_case. Examples: brand, brand_name.

How to structure the model

The coding style from Django suggest that we use this order when we set up the model:

  • Choices
  • The attributes
  • The meta class
  • String method
  • Custom save method
  • Absolute url method
  • Other custom methods you need

Here is an example of a Django model with all fields:

from django.db import models
from django.urls import reverse

class Car(models.Model):
    SEDAN = 0
    COMBI = 1
    CABRIOLET = 2
    
    CHOICES_CHASSIS = (
        (SEDAN, 'Sedan'),
        (COMBI, 'Combi'),
        (CABRIOLET, 'Cabriolet')
    )
    
    brand = models.CharField('Brand', max_length=40)
    chassis = models.IntegerField('Chassis', choices=CHOICES_CHASSIS)
    
    class Meta:
        ordering = ('name',)
    
    def __str__(self):
        return self.brand
    
    def save(self, *args, **kwargs):
        perform_action() # Perform custom action
        super().save(*args, **kwargs) # Perform the actual save
    
    def get_absolute_url(self):
        return reverse('car_detail', kwargs={'pk': self.id})
    
    def perform_action():
        print('This is a action called from the custom save method')

Django's ForeignKey

A very cool thing about the ForeignKey(Reverse relationship) is that you can define something called a "related_name". This let's you add a name to the relationship that is actually meaningful.

Here is an example on how to use the ForeignKey:

from django.db import models

class Brand(models.Model):
    name = models.CharField('Brand', max_length=40)

class Model(models.Model):
    name = models.CharField('Name', max_length=50)
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name='models')

# How to use in a QuerySet

brand = Brand.objects.get(name='BMW')
models = brand.models.all()

The blanks and the null

What is the difference between null and blank?
null = this is the database value. If you set null=True the database will accept null as value.
blank = this is django validation on the field. If you set blank=False (this is default) and you use this in a form, a error will be displayed if the value is empty.

If you want to read more about Django's models I would suggest to get the book Two Scoops of Django. They have written so much good information on the subject.

Comments

Devin Gilbert | Feb 10, 23 09:08

I don't understand where you're getting the value "models" for related_name from (a bit hard to parse what's going on here because we also have `models` being imported from `django.db`, lol). Is the string "models" completely arbitrary? I don't see anything else sharing that name.


Stein Ove Helset | Feb 11, 23 06:19

Hey, I can see the confusion here. The "models" I use in the related_name has nothing to do with the import and is just the brand's models (Like Porsche 911 or BMW M3).
So to clarify this, the related_name could be changed to something like related_name='brand_models') instead :-)

Stein Ove Helset | Feb 11, 23 06:19

Hey, I can see the confusion here. The "models" I use in the related_name has nothing to do with the import and is just the brand's models (Like Porsche 911 or BMW M3).
So to clarify this, the related_name could be changed to something like related_name='brand_models') instead :-)

Add comment

Newsletter

Subscribe to my weekly newsletter. One time per week I will send you a short summary of the tutorials I have posted in the past week.