Django Update Model

Modifying model structure and database schema

🔧 What is Updating a Model?

Updating a model means changing its structure by adding, removing, or modifying fields. Django migrations automatically update your database schema to match your model changes.


# Add a new field to existing model
class Product(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()  # New field added
                                    

Key Update Concepts

Add Fields

Add new columns to tables

field = models.CharField()
✏️

Modify Fields

Change field properties

max_length=200
🗑️

Remove Fields

Delete columns from tables

# Delete field line
🔄

Migrations

Apply changes to database

makemigrations
migrate

🔹 Adding New Fields

Add new fields to your existing model and update the database schema. When adding fields to existing tables, you must provide default values or allow null.

# models.py - Original model
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

# Updated model with new fields
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.TextField(default='No description')  # New field
    stock = models.IntegerField(default=0)  # New field
    created_at = models.DateTimeField(auto_now_add=True)  # New field

Run these commands to apply changes:

python manage.py makemigrations
python manage.py migrate

Output:

Migrations for 'myapp':

myapp/migrations/0002_auto_20240115.py

- Add field description to product

- Add field stock to product

- Add field created_at to product

🔹 Modifying Existing Fields

Change properties of existing fields like max_length, default values, or field types:

# Original field
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

# Modified fields
class Product(models.Model):
    name = models.CharField(max_length=200)  # Increased length
    price = models.DecimalField(max_digits=12, decimal_places=2)  # More digits
    is_active = models.BooleanField(default=True)  # Changed default

After modifying fields:

python manage.py makemigrations
python manage.py migrate

🔹 Removing Fields

Delete fields from your model to remove columns from the database:

# Original model
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    old_field = models.CharField(max_length=50)  # Will be removed

# Updated model - field removed
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    # old_field deleted

⚠️ Warning:

Removing fields permanently deletes data from that column. Make sure to backup important data first!

Output:

Migrations for 'myapp':

myapp/migrations/0003_remove_product_old_field.py

- Remove field old_field from product

🔹 Adding Fields with Null Values

Allow null values for new fields when you don't want to provide defaults:

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    
    # New optional fields
    description = models.TextField(blank=True, null=True)
    discount = models.IntegerField(blank=True, null=True)
    image = models.ImageField(upload_to='products/', blank=True, null=True)

Field Options:

  • blank=True: Allows empty values in forms
  • null=True: Allows NULL in database
  • default: Sets default value for existing rows

🔹 Renaming Fields

Rename fields while preserving data:

# Original model
class Product(models.Model):
    product_name = models.CharField(max_length=100)

# Renamed field
class Product(models.Model):
    name = models.CharField(max_length=100)  # Renamed from product_name

Django will ask during makemigrations:

Did you rename product.product_name to product.name? [y/N]

Answer 'y' to preserve the data, or 'N' to create a new field.

🔹 Adding Relationships

Add foreign keys and relationships to existing models:

# Create new related model
class Category(models.Model):
    name = models.CharField(max_length=100)

# Update existing model with relationship
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    
    # New relationship field
    category = models.ForeignKey(
        Category,
        on_delete=models.SET_NULL,
        null=True,
        blank=True
    )

Steps to add relationships:

  1. Create the related model (Category)
  2. Add ForeignKey field to existing model
  3. Run makemigrations and migrate
  4. Optionally populate the relationship data

🔹 Migration Commands

Essential commands for managing model updates:

# Create migration files
python manage.py makemigrations

# Apply migrations to database
python manage.py migrate

# Show migration status
python manage.py showmigrations

# View SQL for a migration
python manage.py sqlmigrate myapp 0002

# Revert to a specific migration
python manage.py migrate myapp 0001

# Create empty migration for custom changes
python manage.py makemigrations --empty myapp

🔹 Complete Update Example

A real-world example of updating a model:

# Original Product model
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

# Updated Product model with many changes
class Product(models.Model):
    # Modified field
    name = models.CharField(max_length=200)  # Increased length
    
    # Existing field
    price = models.DecimalField(max_digits=10, decimal_places=2)
    
    # New fields
    sku = models.CharField(max_length=50, unique=True, default='SKU000')
    description = models.TextField(blank=True)
    stock = models.IntegerField(default=0)
    is_active = models.BooleanField(default=True)
    
    # New relationship
    category = models.ForeignKey(
        'Category',
        on_delete=models.SET_NULL,
        null=True,
        blank=True
    )
    
    # New timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.name

🧠 Test Your Knowledge

Which command creates migration files after model changes?