Backend Development 21 min read

Comprehensive Django ORM Guide: Model Definition, Custom Table Names, Indexes, Relationships, Query Optimization, and Validation

This article provides an in‑depth tutorial on using Django's ORM, covering model creation, custom table names, single and composite indexes, one‑to‑many and many‑to‑many relationships, forward and reverse lookups, performance tuning with select_related and prefetch_related, and model validation techniques.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Comprehensive Django ORM Guide: Model Definition, Custom Table Names, Indexes, Relationships, Query Optimization, and Validation

The article introduces Django's ORM capabilities, explaining that a model can create database tables, operate on them, and perform data validation.

Custom Table Name

By default Django generates a table name as app_label_classname (e.g., app01_user ). To override this, define db_table inside the inner Meta class:

class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    class Meta:
        db_table = "user"

Indexes

Single‑column indexes can be added with db_index=True on a field. Composite (joint) indexes are defined via index_together in Meta :

class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    class Meta:
        db_table = "user"
        index_together = [("user", "pwd")]

Only queries that include the leftmost column of a composite index can use the index (e.g., WHERE user='zhangsan' or WHERE user='zhangsan' AND pwd='111' ).

Unique Composite Index

Use unique_together = (("name", "pwd"),) to enforce uniqueness of a column pair.

One‑to‑Many Relationship

class UserType(models.Model):
    name = models.CharField(max_length=32)

class User(models.Model):
    user = models.CharField(max_length=32, db_index=True)
    pwd = models.CharField(max_length=64, db_index=True)
    ut = models.ForeignKey(
        to="UserType",
        to_field="id",
        on_delete=models.CASCADE,
        related_name="cc",
        limit_choices_to={"id__gt": 2},
    )

When a UserType instance is deleted, Django 1.10+ cascades the delete to related User rows if on_delete=models.CASCADE is set.

ForeignKey Parameters

to : target model name.

to_field : target field name.

on_delete : behavior when the referenced row is removed ( CASCADE , DO_NOTHING , PROTECT , SET_NULL , SET_DEFAULT , SET(value) ).

related_name : custom name for reverse relation (e.g., cc ).

related_query_name : name used in reverse lookups (e.g., aa_set if set to aa ).

limit_choices_to : filter options shown in Django admin or ModelForm.

Forward and Reverse Lookups

Forward lookup example:

v1 = models.User.objects.all().values("user", "ut__name")

Reverse lookup example:

v3 = models.UserType.objects.all().values("name", "user__user")

Both can also be performed with explicit loops.

Many‑to‑Many Relationships

Three ways to create many‑to‑many relations:

Let Django create an implicit through table using ManyToManyField :

Manually create an explicit through table:

Manually create a through table and attach it via through and through_fields for finer control (recommended).

ORM Basic CRUD Operations

Examples of creating, reading, updating, and deleting records:

models.Tb1.objects.create(c1='xx', c2='oo')
obj = models.Tb1(c1='xx', c2='oo')
obj.save()
models.Tb1.objects.get(id=123)
models.Tb1.objects.filter(name='seven')
models.Tb1.objects.exclude(name='seven')
models.Tb1.objects.filter(name='seven').update(gender='0')
models.Tb1.objects.filter(name='seven').delete()

Additional QuerySet methods covered include count , range filters ( id__gt , id__lt ), in , isnull , contains , ordering, grouping with annotate , pagination ( [10:20] ), and raw SQL execution via raw() .

Performance Optimization

Using select_related('ut') performs a SQL join and fetches related UserType data in a single query, while prefetch_related('ut') runs two separate queries and caches the related objects, reducing the number of database hits in loops.

Model Validation

Calling full_clean() on a model instance triggers field‑level validation and the clean() hook. An example custom validation ensures the name field is unique:

def clean(self):
    if UserInfo.objects.filter(name=self.name).count():
        raise ValidationError("用户名已经存在", code="cc1")

The validation order is: field regex validation → clean() hook.

Overall, the article serves as a practical reference for Django developers needing detailed guidance on model design, indexing strategies, relationship handling, query optimization, and data validation.

backendPythonDatabaseDjangoORMModelQuery
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.