Django Models

  • A Django model is the built-in feature that Django uses to create tables, their fields, and various constraints.
  • Each model class maps to a single table in the database.
  • Django Model is a subclass of django.db.models.Model and each field of the model class represents a database field (column).
from django.db import models  
  
class Employee(models.Model):  
    first_name = models.CharField(max_length=30)  

4.1 Field types

  • It tells the database what kind of data to store
  • Like Integer, Varchar, Boolean etc
# It is an IntegerField that automatically increments.
models.AutoField()
models.BigAutoField()

# A field to store text-based values.
models.CharField(max_length=10)

# A true/false field. 
models.BooleanField(default=True)


# Range −2,147,483,648 (−2^31) to 2,147,483,647 (2^31 − 1).
models.IntegerField()
# Range 0 to 2,147,483,647 (2^31 − 1)
models.PositiveIntegerField(null=True)
# IntegerField and PositiveIntegerField can store 
# more tha 18-digit in SQLite
# SmallIntegerField, PositiveSmallIntegerField, BigIntegerField
# FloatField

# A large text field. 
# The default form widget for this field is a Textarea.
models.TextField(blank=True)

# It is used for date and time, 
# represented in Python by a datetime.datetime instance.
models.DateTimeField(default=timezone.now)
models.DateTimeField(default=None, null=True)

# It is a CharField that checks that the value is a valid email address.
models.EmailField(max_length=254)

models.JSONField(default=list)

# A CharField for a URL, validated by URLValidator.
models.URLField(max_length=200, default=None, null=True)

Relationship Fields

# M2O - ForeignKey
models.ForeignKey(Manufacturer, on_delete=models.CASCADE)

# M2M
models.ManyToManyField(Product)
models.ManyToManyField(Product, through='ProductCollection')

# O2O
models.OneToOneField(OrderProduct, on_delete=models.SET_DEFAULT

Django Choices

Field.choices

class Person(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

p = Person.objects.create(name="Fred Flintstone", shirt_size="L")
print(p.shirt_size) 
# L
print(p.get_shirt_size_display())
# Large
class Runner(models.Model):
    # choices --> GOLD, SILVER, BRONZE
    MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
    name = models.CharField(max_length=60)
    medal = models.CharField(
        blank=True, choices=MedalType.choices, max_length=10)


MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
MedalType.choices
# [('GOLD', 'Gold'), ('SILVER', 'Silver'), ('BRONZE', 'Bronze')]

Place = models.IntegerChoices('Place', 'FIRST SECOND THIRD')
Place.choices
# [(1, 'First'), (2, 'Second'), (3, 'Third')]
class Card(models.Model):
    class Suit(models.IntegerChoices):
          DIAMOND = 1
          SPADE = 2
          HEART = 3
          CLUB = 4
    suit = models.IntegerField(choices=Suit.choices)
# pip install django-choices

from djchoices import ChoiceItem, DjangoChoices


class Book(models.Model):
    class BookType(DjangoChoices):
        short_story = ChoiceItem('short', 'Short story')
        novel = ChoiceItem('novel', 'Novel')
        non_fiction = ChoiceItem('non_fiction', 'Non fiction')

    author = models.ForeignKey('Author')
    book_type = models.CharField(
        max_length=20, choices=BookType.choices,
        default=BookType.novel
    )

# Person.objects.create(author=my_author, type=Book.BookTypes.short_story)

4.2 Field Options

Field options are the arguments given to each field for applying some constraint or imparting a particular characteristic to a particular Field.

  • Null
    • If True, Django will store empty values as NULL in the database.
    • Default is False.
  • Blank
    • If True, the field is allowed to be blank.
    • Default is False.
  • Default
    • The default value for the field.
    • This can be a value or a callable object.
    • If callable it will be called every time a new object is created.
  • help_text
    • Extra “help” text to be displayed with the form widget.
    • It’s useful for documentation even if your field isn’t used on a form.
  • primary_key
    • If True, this field is the primary key for the model.
    • And default pk(id) will be absent
  • editable
    • If False, the field will not be displayed in the admin or any other ModelForm.
    • They are also skipped during model validation.
    • Default is True.
  • error_messages
    • The error_messages argument lets you override the default messages that the field will raise.
    • Pass in a dictionary with keys matching the error messages you want to override.
  • verbose_name
    • A human-readable name for the field.
    • If the verbose name isn’t given, Django will automatically create it using the field’s attribute name, converting underscores to spaces.
  • db_column
    • The name of the database column to use for this field.
    • If this isn’t given, Django will use the field’s name
  • validators
  • Unique
    • If True, this field must be unique throughout the table.
  • max_length
    • max length of char that can be stored
    • max_length=10 - at max only 10 char can be stored

Blank vs Null

  • By default, both are set to False
  • Null
    • null is database-related
    • Defines if a given database column will accept null values or not
  • Blank
    • blank is validation-related
    • It will be used during forms validation
    • In admin-panel - this field is not mandatory
class Person(models.Model):
    # Don't put null=True
    bio = models.TextField(max_length=500, blank=True)  
    # May add null=True
    birth_date = models.DateField(null=True, blank=True) 
  • NOTE:
    • Avoid using null on string-based fields, such as CharField and TextField.
    • Otherwise, end up having two possible values for “no data” i.e. None and an empty string

verbose_name

  • verbose_name is a human-readable name for the field
  • If the verbose name isn’t given, Django will automatically create it
  • Useful in Admin Panel
first_name = models.CharField(max_length=30)
# First Name

field_name = models.Field(verbose_name = "name")
# Name

first_name = models.CharField("person's first name", max_length=30)
# Person's first name:

Primary key

  • Django has a default PK, id which is automatically created
  • PK is like an Index for the model
  • If any other field has primary_key=True then default pk(id) will be absent
# This field will become primary key for the model.
field_name = models.AutoField(primary_key=True)

Unique key

  • If True, this field must be unique throughout the table.
  • This option is valid on all field types except ManyToManyField and OneToOneField
# Can't save duplicate values in field_name
field_name = models.Field(unique=True)

PK vs UK

  • One model has
    • 1 PK fields
    • Many UK fields
  • Null Value
    • PK don’t accept null value
    • UK accepts null value

4.3 Model definition

from django.db import models

class Posts(models.Model):
    title = models.CharField(max_length=100)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(Person, on_delete=models.CASCADE)

    def was_published_recently(self):
        diff = timezone.now() - datetime.timedelta(days=1) 
        return self.date_posted >=  diff

    def __str__(self):
        return self.title
        
    class Meta:
        ordering = ['title']

    def save(self, *args, **kwargs):
        do_something()
        # Call the "real" save() method.
        super().save(*args, **kwargs) 
        do_something_else()
  • Efficient model import
# Can be anywhere, Order not necessary
ingredients = models.ManyToManyField('Ingredient')
# Also solves Circular import issue

# Ingredient model should be defined before this model
ingredients = models.ManyToManyField(Ingredient)

4.4 ForeignKey.on_delete

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

class Comment(models.Model):
    content = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
  • CASCADE
    • Whenever the referenced object is deleted, the objects referencing it are deleted as well.
    • On Post delete, all Comments are also deleted
  • SET_NULL
    • Set the ForeignKey null, this is only possible if null is True.
  • SET_DEFAULT
    • Set the ForeignKey to its default value, a default for the ForeignKey must be set.
  • DO_NOTHING
    • Do nothing - Consistency must be handled elsewhere
  • PROTECT
    • Prevent deletion of the referenced object by raising ProtectedError
  • RESTRICT
    • Prevent deletion of the referenced object by raising RestrictedError
  • SET()
    • Set the ForeignKey to the value passed to SET()

4.5 Meta Class in Django Models

  • It is the inner class of your model class.
  • It is used to change the behavior of your model fields
from django.db import models

class Common(models.Model):
    name = models.CharField(max_length=100)
    class Meta:
        abstract = True

class Student(Common):
    rollno = models.IntegerField()
    class Meta:
        verbose_name = "stu"
        ordering = [-1]

  1. Abstract Base Class
    • Abstract Base Class are useful when you want to put some common information into a number of other models
    • After set abstract=True, now it becomes an abstract class not a model, so now you can’t generate a database table
  2. verbose_name
    • verbose_name is basically a human-readable name for your model
  3. ordering
    • ordering = ['-date_posted'] –> Descending order
    • ordering = ['-pub_date', ‘author’]
      • Order by pub_date descending, then by author ascending
  4. app_label
  5. proxy
  6. permissions
  7. …read more

4.6 Model instance methods

  • __str__()
    • Return a nice, human-readable representation of the model from the str() method
  • save()
    • Override save function in MODEL
class Student(common):
    rollno = models.IntegerField()
    modified_datetime = models.DateTimeField(null=True)

    def save(self, *args, **kwargs):
        if self.pk: # --> obj is updated
            self.modified_datetime = get_curtime()
        # self.pk is None --> if obj is created
        # super(ProductCollection, self).save(*args, **kwargs)
        super().save(*args, **kwargs)

models.py

from django.db import models

from django.contrib.auth.models import User
from django.contrib.auth import get_user_model

from django.contrib.auth.models import AbstractUser

from django.utils import timezone
from django.core.exceptions import ValidationError

from django.db.models import Q

Reference