Database Models in Django

What are Django Models?

Django models are Python classes that define the structure of your database tables. Each model class maps to a single database table. The attributes (fields) in the model class represent the columns in the database table, and Django automatically takes care of creating the actual database schema for you.

Use Case:

Django models are used when we need to store data permanently in a database. They define the structure of the data using Python classes and provide a high-level, Pythonic way to interact with the database—eliminating the need to write raw SQL queries.

Django Model Example
# Django model for storing student info
from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    enrolled = models.BooleanField(default=True)

Django Model Fields

This example showcases different field types in Django models, including CharField, TextField, IntegerField, and others, for storing various data types like text, numbers, dates, and files. The __str__ method is defined to return a string representation of the model instance based on the char_field. Below is a simple example demonstrating how to define a model in Django to create fields in your database.

Field Types Example
# Common fields used in Django models for various data types
from django.db import models

# null=True allows storing None, while null=False stores an empty string ('') for text fields.
# blank=True makes the field optional in forms,while blank=False makes it required.

class ExampleModel(models.Model):
    # CharField: For storing short text, requires a max_length attribute.
    char_field = models.CharField(max_length=100, null=True, blank=True)     
    
    # TextField: For storing long text with no limit on length.
    text_field = models.TextField()                     
    
    # IntegerField: For storing integer (whole) values.
    integer_field = models.IntegerField()              
        
    # DecimalField: For storing fixed-point decimal numbers with precision.
    decimal_field = models.DecimalField(max_digits=5, decimal_places=2) 
    
    # BooleanField: For storing True/False values (a boolean).
    boolean_field = models.BooleanField()              
    
    # DateField: For storing date values (year, month, day).
    date_field = models.DateField()                     
        
    # TimeField: For storing time only (hour, minute, second).
    time_field = models.TimeField()                     
    
    # EmailField: For storing valid email addresses.
    email_field = models.EmailField()                   
        
    # FileField: For handling file uploads (e.g., documents).
    file_field = models.FileField(upload_to='files/')  
    
    # ImageField: For handling image uploads.
    image_field = models.ImageField(upload_to='images/')  

    # __str__ method to represent the model instance by the char_field.
    def __str__(self):
        return self.char_field

Django Model Relationship Fields

Django model relation fields are used to connect one model to another. They help define relationships between tables in the database. The main relation fields are:

ForeignKey: A one-to-many relationship (e.g., each book belongs to one author).

OneToOneField: A one-to-one relationship (e.g., each user has one profile).

ManyToManyField: Many-to-many relationship (e.g., students and courses can be linked to each other).

1. ForeignKey Example (One-to-Many Relationship)

ForeignKey Example
# Represents an author who can write multiple books
class Author(models.Model):
    name = models.CharField(max_length=100)

# Each book is linked to a single author
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

2. OneToOneField Example (One-to-One Relationship)

OneToOneField Example
# Defines a user with essential account details
class User(models.Model):
    username = models.CharField(max_length=100)

# Stores extra profile details linked to a single user
class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField()

3. ManyToManyField Example (Many-to-Many Relationship)

ManyToManyField Example
# Represents a course that can have multiple students
class Course(models.Model):
    name = models.CharField(max_length=100)

# Represents a student who can enroll in many courses
class Student(models.Model):  
    name = models.CharField(max_length=100)
    courses = models.ManyToManyField(Course)

What is a Base Class in Django?

In Django, a BaseClass is a custom class that contains common fields or methods used by other models. It helps avoid repetition and simplifies code by allowing multiple models to inherit shared functionality.

Base Model Example
from django.db import models

class BaseModel(models.Model):
    is_active = models.BooleanField(default=True)
    is_deleted = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

# Course model inherits common fields from BaseModel.
class Course(BaseModel):
    title = models.CharField(max_length=100)
    description = models.TextField()
    duration = models.IntegerField()

What is an AbstractUser Model?

In Django, AbstractUser is a built-in model that gives you a basic user setup with common fields like username, password, email, first name, last name, and permissions. You can use it to create your own custom user model by adding more fields or changing existing ones, while still using Django's built-in login and user features.

AbstractUser Model Example
from django.contrib.auth.models import AbstractUser
from django.db import models

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class MyUser(AbstractUser):
    class Role(models.IntegerChoices):
        ADMIN = 1, 'Admin'
        USER = 2, 'User'

    role = models.IntegerField(choices=Role.choices, default=Role.USER)

    class Meta:
        ordering = ['role', 'id']
        verbose_name = 'My User'
        verbose_name_plural = 'My Users'

    def __str__(self):
        return f"{self.role} - {self.username}"

Exercise

  1. Fill in the Blanks:
    • - In Django, a __________ is a Python class that maps to a database table.
    • - The field used in Django models to store long text data without length limits is __________.
    • - A __________ relationship is defined using ForeignKey in Django models.
    • - Django's AbstractUser model can be extended to create a __________ user model.
    • - To store multiple choices in a model field, Django provides the __________ option.