Topic 07 / 12

The Django ORM: Defining Your Database with Models

~18 min read  //  Django Part 1 Series  //  Coding India

1. What is an ORM?

An ORM (Object-Relational Mapper) is a programming layer that translates between two completely different worlds: the world of Python objects and the world of relational database tables.

Without an ORM, to store a blog post you would write raw SQL like this:

INSERT INTO blog_post (title, body, created_at)
VALUES ('My First Post', 'Hello world...', NOW());

With Django’s ORM, you write pure Python instead:

Post.objects.create(title='My First Post', body='Hello world...')

The ORM automatically generates and executes the SQL for you. This has three major advantages: you write less code, your code is database-agnostic (switch from SQLite to PostgreSQL by changing one line in settings.py), and you are protected from SQL injection attacks by default.

2. Defining Your First Model

Open blog/models.py and define a Post model for our blog:

# blog/models.py
from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    # CharField stores short strings. max_length is required and sets
    # the database column's character limit.
    title = models.CharField(max_length=200)

    # SlugField stores URL-friendly strings like 'my-first-post'.
    # unique=True ensures no two posts share the same URL.
    slug = models.SlugField(max_length=200, unique=True)

    # TextField stores unlimited text. No max_length required.
    body = models.TextField()

    # ForeignKey creates a many-to-one relationship: many Posts can
    # belong to one User (the author).
    # on_delete=CASCADE means: if the User is deleted, delete their posts too.
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')

    # auto_now_add=True sets this field to the current timestamp when
    # the record is first created, and never changes it afterwards.
    created_at = models.DateTimeField(auto_now_add=True)

    # auto_now=True updates this field to the current timestamp every
    # time the record is saved.
    updated_at = models.DateTimeField(auto_now=True)

    # BooleanField stores True/False. We use this to draft posts
    # without publishing them.
    published = models.BooleanField(default=False)

    def __str__(self):
        # This controls how a Post object is displayed in the admin
        # panel and in the Python shell.
        return self.title

    class Meta:
        # Order posts by newest first in all queries by default.
        ordering = ['-created_at']

3. Common Field Types Reference

FieldUse CaseKey Options
CharFieldShort text (name, title, email)max_length (required)
TextFieldLong text (article body, bio)
IntegerFieldWhole numbersdefault
DecimalFieldMoney, precise decimalsmax_digits, decimal_places
BooleanFieldTrue/False flagsdefault
DateTimeFieldDate and timeauto_now_add, auto_now
ImageFieldUploaded images (stores file path)upload_to
ForeignKeyMany-to-one relationshipon_delete, related_name
ManyToManyFieldMany-to-many relationship (tags)related_name

4. How Django Maps Models to Tables

When Django reads your Post model, it maps it to a database table with the following naming convention: {app_name}_{model_name_lowercase}. So our Post model in the blog app becomes the table blog_post.

Each field on the model becomes a column in the table. Django automatically adds an id column (a BigAutoField primary key) unless you explicitly define one. The author ForeignKey becomes an author_id integer column that stores the primary key of the related User record.