DEV Community

Cover image for Designing Better Models in Django
Vicente G. Reyes
Vicente G. Reyes

Posted on • Originally published at vgr.icvn.tech

Designing Better Models in Django

Photo by Christopher Gower on Unsplash

Introduction

Defining database models is the most critical part of a new project. Django’s coding style ives us a recommended way to create models for our apps which I only discovered today thanks to LearnDjango.😁 Creating database models may not be simple to devs who haven’t laid hands on Django yet, but I’ll try my best to make sense. 😁

Learn Django is one of my go-to resources in being a Django developer. If you haven’t checked out the article about my top Django resources, you can check it here.

Model and Field Names

Models will always start with a Capital letter and will always be singular because they should only represent a single object and be using underscores and not a camelCase.

from django.db import models

class City(models.Model):
    town_name = models.CharField(max_length=50)
Enter fullscreen mode Exit fullscreen mode

Common Methods

Defining models is not easy nor should not be difficult. Next we add the __str__ and get_absolute_url() methods.

Defining the str method makes the model human-readable in the Django admin.

Defining the get_absolute_url() method tells Django how to calculate the canonical URL for the model. This method should return a string that references a view on the site. It’s also a good practice to use get_absolute_url() on the templates instead of hard-coding them.

<a href="town/{{ object.id }]}/">{{ object.town_name }}</a> # wrong

<a href="{{ object.get_absolute_url }}/">{{ object.town_name }}</a> # better

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

class City(models.Model):
    town_name = models.CharField(max_length=50)

    def __str__(self): # new
        return self.town_name

    def get_absolute_url(self):
        return reverse('town', kwargs={"town_name": self.town_name})
Enter fullscreen mode Exit fullscreen mode

Explicit Naming

Explicit is better than implicit

There are two ways to implicitly set the human-readable name for each field which Django does by automatically converting underscores to spaces. One is to use verbose_name(); if the field type is not OneToOneField, ManyToMany or ForeignKey, you can set it as the first positional argument.

from django.db import models 

class City(models.Model): 
    town_name = models.CharField(
    max_length=50,
    verbose_name='town name',
    )

    def __str__(self):
        return self.town_name 

    def get_absolute_url(self): 
        return reverse('town', kwargs={"town_name": self.town_name})
Enter fullscreen mode Exit fullscreen mode

If a model uses ForeignKey, the model will have access to a Manager that returns all instances of the first model. This model returns QuerySets which can be filtered to retrieve objects.

Example:

>>> a = City.objects.get()
Enter fullscreen mode Exit fullscreen mode
...
class Mayor(models.Model):
    first_name = models.CharField('first name', max_length=30)
    last_name = models.CharField('last name', max_length=30)
    city = models.ForeignKey(
        City,
        on_delete=models.CASCADE,
        related_name='mayors',
        related_query_name='human',
        )

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

    def get_absolute_url(self):
        return reverse('town_mayor', kwargs={'town_name': self.town_name})
Enter fullscreen mode Exit fullscreen mode

References

In [1]: from blog.source.models import Category 
In [2]: a = Category.objects.get(name='python') 
In [3]: print(a) python
Enter fullscreen mode Exit fullscreen mode

Top comments (0)