Model Fields & Types

Difficulty: Beginner

Django models are Python classes that define the structure of your database tables. Each model class inherits from django.db.models.Model, and each class attribute represents a database column. Django's ORM (Object-Relational Mapper) handles the translation between Python objects and SQL database operations, so you write Python code instead of raw SQL.

Django provides a rich set of field types that map to database column types. CharField stores short text and requires a max_length argument. TextField stores unlimited text and is ideal for large content like article bodies or descriptions. IntegerField stores integers, while FloatField and DecimalField store decimal numbers (DecimalField is preferred for financial data because it avoids floating-point precision issues). BooleanField stores True/False values. DateField and DateTimeField store date and date-time values respectively.

Every field accepts common keyword arguments. 'blank=True' means the field can be left empty in forms (validation level). 'null=True' means the database column allows NULL values (database level). For string fields, Django convention is to use blank=True without null=True, because Django stores empty strings rather than NULL for text fields. 'default' sets a default value. 'unique=True' enforces uniqueness at the database level. 'choices' limits the field to a predefined set of values.

The 'choices' parameter is powerful for fields with a fixed set of options. You define choices as a sequence of two-tuples where the first element is the value stored in the database and the second is the human-readable label. Django provides the get_FOO_display() method on model instances to retrieve the human-readable label for a choices field.

Specialized fields include EmailField (validates email format), URLField (validates URL format), SlugField (for URL-friendly strings), FileField and ImageField (for file uploads), UUIDField (for universally unique identifiers), JSONField (for storing JSON data), and IPAddressField/GenericIPAddressField (for IP addresses). These fields provide both database storage and validation.

The inner Meta class configures model-level options. 'ordering' sets the default sort order for QuerySets. 'verbose_name' and 'verbose_name_plural' set human-readable names for the admin. 'db_table' overrides the auto-generated table name. 'unique_together' (or UniqueConstraint) enforces multi-column uniqueness. 'indexes' defines database indexes for query performance.

Every model should define a __str__() method that returns a meaningful string representation. This is used in the admin interface, the shell, and debugging output. Without it, your objects will display as unhelpful strings like 'Product object (1)'.

Code examples

Common Field Types

from django.db import models

class Product(models.Model):
    # Text fields
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    slug = models.SlugField(unique=True)

    # Numeric fields
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.IntegerField(default=0)
    weight = models.FloatField(null=True, blank=True)

    # Boolean field
    is_active = models.BooleanField(default=True)

    # Date fields
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # File fields
    image = models.ImageField(upload_to='products/', blank=True)

    def __str__(self):
        return self.name

This model demonstrates the most common field types. auto_now_add=True sets the date when the object is first created. auto_now=True updates the date every time the object is saved. DecimalField is used for price to avoid floating-point issues.

Choices Field

from django.db import models

class Order(models.Model):
    class Status(models.TextChoices):
        PENDING = 'pending', 'Pending'
        PROCESSING = 'processing', 'Processing'
        SHIPPED = 'shipped', 'Shipped'
        DELIVERED = 'delivered', 'Delivered'
        CANCELLED = 'cancelled', 'Cancelled'

    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.PENDING,
    )
    total = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'Order #{self.pk} - {self.get_status_display()}'

TextChoices provides an enum-like syntax for defining choices. The first value in each choice is stored in the database, the second is the display label. Use get_status_display() to get the human-readable label.

Meta Class Options

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    content = models.TextField()
    author = models.CharField(max_length=100)
    published_at = models.DateTimeField()
    category = models.CharField(max_length=50)

    class Meta:
        ordering = ['-published_at']  # Default sort: newest first
        verbose_name = 'Article'
        verbose_name_plural = 'Articles'
        unique_together = ['slug', 'category']  # Composite unique
        indexes = [
            models.Index(fields=['published_at']),
            models.Index(fields=['category', 'published_at']),
        ]

    def __str__(self):
        return self.title

The Meta class controls model behavior. ordering sets default QuerySet ordering. unique_together enforces uniqueness across multiple columns. indexes improve query performance for frequently searched fields.

Specialized Fields

import uuid
from django.db import models

class UserProfile(models.Model):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    email = models.EmailField(unique=True)
    website = models.URLField(blank=True)
    bio = models.TextField(max_length=500, blank=True)
    metadata = models.JSONField(default=dict, blank=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)

    def __str__(self):
        return self.email

UUIDField with primary_key=True replaces the auto-incrementing integer ID. EmailField and URLField add validation. JSONField stores arbitrary JSON data. GenericIPAddressField supports both IPv4 and IPv6.

Key points

Concepts covered

Model, Fields, CharField, TextField, IntegerField, Meta