Django

Lesson 02

Model fields and constraints

Use precise fields, validation intent, and database constraints so the model protects real domain rules.

Good Code

reviews/models.py
from django.conf import settings
from django.db import models
from django.db.models import Q


class Review(models.Model):
    class Status(models.TextChoices):
        DRAFT = "draft", "Draft"
        PUBLISHED = "published", "Published"

    title = models.CharField(max_length=120)
    slug = models.SlugField(max_length=140)
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.DRAFT,
    )
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    published_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["author", "slug"],
                name="unique_review_slug_per_author",
            ),
            models.CheckConstraint(
                condition=Q(status="draft") | Q(published_at__isnull=False),
                name="published_reviews_have_date",
            ),
        ]

Bad Code

reviews/models.py
from django.db import models


class Review(models.Model):
    title = models.TextField(null=True, blank=True)
    slug = models.CharField(max_length=255, null=True, blank=True)
    status = models.CharField(max_length=255, null=True, blank=True)
    author_id = models.IntegerField()
    published_at = models.DateTimeField(null=True, blank=True)

Review Notes

What to review

Good Code

The good version chooses field types that match the data, links the author through a real relationship, and pushes uniqueness and publication rules into the database.

Bad Code

The bad version stores almost everything as optional text or raw IDs. It leaves important invariants to scattered application code.

Takeaways

  • A Django model should express business invariants, not just provide loose columns.