Skip to content

Models, Relations, & Inheritance


Django Models

In Django, the model is the object mapped to the database.

picture

Django Model

Book : Mastering Django by Nigel George - 2022

Supported Databases

Django 3.0 and higher officially supports five databases:

  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle
  • MariaDB

There are also several third-party applications available if you need to connect to an unofficially supported database.


Model

Django Field Types Django Field Types

Working with model field relationships

Django provides three relationship types for linking tables:

  • Many–to–one
  • Many–to–many
  • One–to–one

A many-to-one relationship is defined by using a ForeignKey field, and the other two relationship types are defined using the self-explanatory ManyToManyField and OneToOneField. These fields are named appropriately after the relationship type that they represent.

The three field types — ForeignKey, ManyToManyField, and OneToOneField.

# /becoming_a_django_entdev/chapter_3/models.py
...
class Vehicle(models.Model):
    ...
    vehicle_model = models.ForeignKey(
        VehicleModel,
        on_delete = models.CASCADE,
        verbose_name = 'Model',
        related_name = 'model_vehicle',
        blank = True,
        null = True,
    )
    engine = models.ForeignKey(
        Engine,
        on_delete = models.CASCADE,
        verbose_name = 'Engine',
        related_name = 'engine_vehicle',
        blank = True,
        null = True,
    )
# /becoming_a_django_entdev/chapter_3/models.py
...
class Engine(models.Model):
    ...
    vehicle_model = models.ForeignKey(
        VehicleModel,
        on_delete = models.CASCADE,
        verbose_name = 'Model',
        related_name = 'model_engine',
        blank = True,
        null = True,
    )
# /becoming_a_django_entdev/chapter_3/models.py
...
class Seller(models.Model):
    name = models.CharField(
        verbose_name = 'Seller Name',
        max_length = 150,
        blank = True,
        null = True,
    )
    vehicle = models.ManyToManyField(
        Vehicle,
        verbose_name = 'Vehicles',
        related_name = 'vehicle_sellers',
        related_query_name = 'vehicle_seller',
        blank = True,
    )

Customizing models

Writing methods

Writing a model method is similar to writing a Meta subclass, except instead of writing a class, we are now writing a function inside that class using the def keyword.

The four most helpful and most used methods are defined here:

  • def save(self, *args, **kwargs)
  • def delete(self, *args, **kwargs)
  • def get_absolute_url(self)
  • def __str__(self)

Decorators

A decorator is a standard Python design pattern that allows developers to extend the functionality of an object without permanently changing the behavior of that object. The concept of decorators can be applied to virtually any class or method that exists in a project.

  • @property

    A @property decorator allows us to write a method to act as a regular property of a model instance, rather than act as a function.

Extending models

Extending a model is a way to write a set of fields and methods that can be shared in many different classes. This is also known as inheritance, which is a fundamental principle of the Python language, letting us write code once and reuse it over and over again. It is also a way to reuse or modify a class provided by Django itself, such as the built-in User model, which is a very common model to extend.

Using the Django shell

Generating a SECRET_KEY variable

A SECRET_KEY variable in Django is used as a hash to secure things, such as your sessions, cookie storage, password tokenization, and all other methods of cryptographic signing that act to secure your site. Instead of using an online tool to generate this key, where the transmission either to or from that source could be compromised, you could generate your own using the Django shell.

$ python3 manage.py shell
$ from secret_key_generator import secret_key_generator
$ print(secret_key_generator.generate())

Using the Meta subclass

Model metadata is an inner class of a model called Meta.

It is not required and completely optional but it does make using Django much more useful when it is included in your models. Metadata provides all of the "other" information that is not defined in model field arguments. The settings that are defined inside this class are called meta options, and there are quite a lot to choose from.

from django.db import models

class MyModel(models.Model):
    # Model fields here

    class Meta:
        verbose_name = "Custom Singular Name"
        verbose_name_plural = "Custom Plural Name"
        ordering = ['field1', '-field2']
        unique_together = ['field1', 'field2']
        indexes = [
            models.Index(fields=['field1'], name='field1_idx'),
            models.Index(fields=['field2'], name='field2_idx'),
        ]
        permissions = [
            ('can_view', 'Can view records'),
            ('can_edit', 'Can edit records'),
        ]

Django auto_now vs auto_now_add

In Django, auto_now and auto_now_add are options for DateTimeField and DateField fields in models. They are used to automatically set the field to the current date and time when an object is created or updated. Here's the difference between the two:

1. auto_now: When this option is set to True, the field will be updated with the current date and time every time the model's save() method is called. This means that the field will always reflect the most recent time the object was saved to the database.

2. auto_now_add: When this option is set to True, the field will be set to the current date and time when the object is first created, and it will not be updated subsequently. This is useful for fields that should have a fixed creation timestamp.

Here's an example of how they can be used in a Django model:

from django.db import models

class MyModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    # Other fields...

In this example, created_at will be set to the current timestamp when an instance of MyModel is created, and updated_at will be updated with the current timestamp every time the instance is saved.

When to use auto_now and auto_now_add depends on the specific requirements of your application:

  • Use auto_now_add when you want to record the time when an object was created and you don't want this field to be updated later.

  • Use auto_now when you want to keep track of the last time an object was updated.

However, there are situations where you might not want to use these options:

  • Avoid using auto_now and auto_now_add if you need to manually set these fields in some cases. For example, if you're importing data and need to set specific creation or update timestamps, using these options will override your manual settings.

  • Avoid using auto_now if you have cases where you want to update other fields without updating the timestamp field.

In summary, auto_now and auto_now_add are useful shortcuts for handling timestamp fields in Django models, but you should consider your application's specific requirements and potential edge cases when deciding whether to use them.

Example of auto_now and auto_add_now

In a typical blog model scenario, you would want to record both the creation date of the blog post and the last modification date. For this purpose, you can use both auto_now_add and auto_now options for DateTimeField.

Here's how you might implement it:

from django.db import models

class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

In this model:

  • created_at will automatically store the date and time when the blog post is first created.
  • updated_at will automatically update to the current date and time whenever the blog post is saved.

This setup ensures that you have both the creation date and the last modification date stored for each blog post. It's a common and efficient approach for most blog applications.

If you only need the creation date and don't care about the last modification date, you can just use auto_now_add=True for the created_at field:

class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

This simplifies the model, but you lose the ability to track when the post was last updated.

Ultimately, the best option depends on your specific requirements. If you need both creation and modification dates, the first approach is appropriate. If you only need the creation date, you can use the simplified version.

ModelAdmin class

In Django admin, readonly_fields and fields are attributes of the ModelAdmin class that allow you to customize which fields are displayed and whether they are editable in the admin interface.

attributes

  1. fields
  2. readonly_fields
  3. list_display
  4. ordering
  5. list_per_page

Django Category

Static choices

from django.db import models

class YourModel(models.Model):
    CHOICES = (
        ('option1', 'Option 1'),
        ('option2', 'Option 2'),
        ('option3', 'Option 3'),
    )

    your_field = models.CharField(max_length=20, choices=CHOICES)

Advanced Model

Mastering Django by Nigel George 2022, chapter 9

Django’s QuerySet API provides a comprehensive array of methods and functions for working with data.

Methods that return QuerySets

Methods that Don't return QuerySets

Model Managers

A Manager is a Django class that provides the interface between database query operations and a Django model. Each Django model is provided with a default Manager named objects.

Tips

newevent = Event.objects.get(name="Xmas Barbeque")
joneses = MyClubUser.objects.filter(last_name='Jones')

In each example, objects is the default Manager for the model instance.

Model Methods

Django’s Model class comes with many built-in methods. We have already used some of them — save(), delete(), __str__() and others. Where manager methods add table-level functionality to Django’s models, model methods add row-level functions that act on individual instances of the model.

There are two common cases where you want to play with model methods:

  1. When you want to add business logic to the model by adding custom model methods; and
  2. When you want to override the default behavior of a built-in model method.

Reference

Becoming an Enterprise Django Developer by Michael Dinder (pg-122)