Skip to main content

Migration Guide

Migrate your existing Django project to Django-CFG and unlock type-safe configuration, modern admin interface, and powerful built-in features.

โš ๏ธ Note: This guide uses simplified examples. For production, use YAML-based configuration as shown in Configuration Guide and First Project.

Migration Strategiesโ€‹

Choose the migration approach that best fits your project:

Best for: New features, major refactoring, or when you want all Django-CFG benefits immediately.

Pros:

  • โœ… Get all Django-CFG features instantly
  • โœ… Clean, modern project structure
  • โœ… No legacy configuration issues
  • โœ… Built-in best practices

Cons:

  • โš ๏ธ Requires data migration
  • โš ๏ธ More initial work

Option 2: Gradual Migrationโ€‹

Best for: Large existing projects, production systems, or when you need minimal disruption.

Pros:

  • โœ… Minimal disruption to existing code
  • โœ… Gradual feature adoption
  • โœ… Keep existing data and structure
  • โœ… Lower risk

Cons:

  • โš ๏ธ Slower to get full benefits
  • โš ๏ธ May have configuration conflicts

Option 3: Side-by-Side Comparisonโ€‹

Best for: Learning Django-CFG, evaluating features, or planning a migration.

Pros:

  • โœ… No risk to existing project
  • โœ… Perfect for learning
  • โœ… Easy feature comparison
  • โœ… Can cherry-pick features

Cons:

  • โš ๏ธ Doesn't migrate existing project
  • โš ๏ธ Requires maintaining two codebases

Option 1: Fresh Start Migrationโ€‹

Step 1: Create New Django-CFG Projectโ€‹

# Create new project with Django-CFG
django-cfg create-project "My Migrated Project"
cd my-migrated-project

Step 2: Export Data from Old Projectโ€‹

# In your old project directory
python manage.py dumpdata --natural-foreign --natural-primary > data_export.json

# Export specific apps (recommended)
python manage.py dumpdata auth.User > users.json
python manage.py dumpdata myapp > myapp_data.json

Step 3: Copy Your Appsโ€‹

# Copy your custom apps to new project
cp -r /path/to/old/project/myapp ./
cp -r /path/to/old/project/anotherapp ./

Step 4: Update Configurationโ€‹

# config.py in new project
from django_cfg import DjangoConfig, DatabaseConfig

class MyConfig(DjangoConfig):
project_name: str = "My Migrated Project"
secret_key: str = "<from-yaml-config>" # Set via environment/config.yaml
debug: bool = False

# Add your custom apps
project_apps: list[str] = [
"myapp",
"anotherapp",
]

# Copy database settings from old project
databases: dict[str, DatabaseConfig] = {
"default": DatabaseConfig(
engine="django.db.backends.postgresql",
name="<from-yaml-config>" # Set via environment/config.yaml,
user="<from-yaml-config>" # Set via environment/config.yaml,
password="<from-yaml-config>" # Set via environment/config.yaml,
host="<from-yaml-config>" # Set via environment/config.yaml,
port=5432,
)
}

config = MyConfig()

Step 5: Import Dataโ€‹

# Run migrations first
python manage.py migrate

# Import your data
python manage.py loaddata users.json
python manage.py loaddata myapp_data.json

Step 6: Test and Verifyโ€‹

# Validate configuration
python manage.py validate_config

# Test your app
python manage.py runserver

# Check admin interface
python manage.py createsuperuser
# Visit http://localhost:8000/admin/

Option 2: Gradual Migrationโ€‹

Step 1: Install Django-CFGโ€‹

# In your existing project
pip install django-cfg

Step 2: Create Configuration Classโ€‹

Create config.py in your project root:

# config.py
from django_cfg import DjangoConfig
from typing import List

class MyConfig(DjangoConfig):
"""Gradual migration configuration"""

# Copy existing settings with type hints
project_name: str = "Existing Project"
secret_key: str = "your-existing-secret-key" # Copy from old settings
debug: bool = True # Copy from old settings

# Copy your INSTALLED_APPS
project_apps: List[str] = [
"myapp",
"anotherapp",
# ... your existing apps
]

# Copy database configuration
# (Convert your existing DATABASES setting)

config = MyConfig()

Step 3: Backup Current Settingsโ€‹

# Backup your current settings
cp settings.py settings_backup.py

Step 4: Replace Settings Fileโ€‹

# settings.py
from config import config

# Import all Django-CFG generated settings
globals().update(config.get_all_settings())

# Keep any custom settings that Django-CFG doesn't handle
CUSTOM_SETTING = "custom_value"
THIRD_PARTY_SETTING = "third_party_value"

# Temporarily keep old settings that you haven't migrated yet
# TODO: Migrate these to config.py
# OLD_SETTING = "old_value"

Step 5: Test Migrationโ€‹

# Test that everything still works
python manage.py check
python manage.py runserver

Step 6: Gradual Feature Adoptionโ€‹

Enable Django-CFG features one by one:

# config.py - Add features gradually
from django_cfg import DjangoConfig, UnfoldConfig, SpectacularConfig

class MyConfig(DjangoConfig):
# ... existing settings ...

# Week 1: Enable beautiful admin
unfold: UnfoldConfig | None = UnfoldConfig()

# Week 2: Enable API documentation
spectacular: SpectacularConfig | None = SpectacularConfig()

# Week 3: Enable built-in modules
enable_support: bool = True
enable_accounts: bool = True

# Week 4: Enable advanced features
enable_newsletter: bool = True
enable_leads: bool = True

Step 7: Clean Up Old Settingsโ€‹

Remove old settings from settings.py as you migrate them to config.py:

# settings.py - Keep getting smaller
from config import config
globals().update(config.get_all_settings())

# Only custom settings remain
CUSTOM_MIDDLEWARE = ["myapp.middleware.CustomMiddleware"]

Option 3: Side-by-Side Comparisonโ€‹

Step 1: Create Reference Projectโ€‹

# Create Django-CFG project for comparison
mkdir django-cfg-reference
cd django-cfg-reference
django-cfg create-project "Reference Project"

Step 2: Compare Configurationsโ€‹

# Compare your old settings.py with config.py
# Look for patterns and improvements

# Old settings.py (500+ lines)
DEBUG = True
SECRET_KEY = "..."
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ... lots of configuration
}
}
# ... 400+ more lines

# New config.py (50 lines)
class MyConfig(DjangoConfig):
debug: bool = True
secret_key: str = "<from-yaml-config>" # Set via environment/config.yaml
databases: dict[str, DatabaseConfig] = {
"default": DatabaseConfig(
engine="django.db.backends.postgresql",
name="<from-yaml-config>" # Set via environment/config.yaml,
# ... type-safe configuration
)
}

Step 3: Feature Comparisonโ€‹

Test Django-CFG features in the reference project:

# Test admin interface
python manage.py runserver
# Visit http://localhost:8000/admin/

# Test API documentation
# Visit http://localhost:8000/api/docs/

# Test CLI commands
python manage.py info
python manage.py validate_config

Step 4: Plan Migrationโ€‹

Create a migration plan based on your comparison:

# Migration Plan

## Phase 1: Core Configuration (Week 1)
- [ ] Convert settings.py to config.py
- [ ] Add type hints to all settings
- [ ] Test basic functionality

## Phase 2: Admin Interface (Week 2)
- [ ] Enable Unfold admin
- [ ] Customize admin interface
- [ ] Train team on new admin

## Phase 3: API Features (Week 3)
- [ ] Enable API documentation
- [ ] Set up API zones
- [ ] Generate API clients

## Phase 4: Built-in Modules (Week 4)
- [ ] Enable support system
- [ ] Enable user management
- [ ] Enable newsletter system

Common Migration Patternsโ€‹

From django-environโ€‹

# Old (django-environ)
import environ
env = environ.Env()
DEBUG = env.bool('DEBUG', default=False)
SECRET_KEY = env('SECRET_KEY')
DATABASE_URL = env('DATABASE_URL')

# New (Django-CFG)
from django_cfg import DjangoConfig

class MyConfig(DjangoConfig):
debug: bool = False
secret_key: str = "<from-yaml-config>" # Set via environment/config.yaml
database_url: str = "<from-yaml-config>" # Set via environment/config.yaml

From python-decoupleโ€‹

# Old (python-decouple)
from decouple import config
DEBUG = config('DEBUG', default=False, cast=bool)
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')])

# New (Django-CFG)
from django_cfg import DjangoConfig
from typing import List

class MyConfig(DjangoConfig):
debug: bool = False
secret_key: str = "<from-yaml-config>" # Set via environment/config.yaml
security_domains: List[str] = ["myapp.com"] # Auto-generates ALLOWED_HOSTS, CORS, SSL

From django-configurationsโ€‹

# Old (django-configurations)
from configurations import Configuration

class Development(Configuration):
DEBUG = True
SECRET_KEY = 'dev-key'

# New (Django-CFG)
from django_cfg import DjangoConfig

from .environment import env

class MyConfig(DjangoConfig):
debug: bool = True
secret_key: str = env.secret_key # Loaded from config.yaml

Complex Database Configurationโ€‹

# Old settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
'OPTIONS': {
'sslmode': 'require',
},
},
'analytics': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('ANALYTICS_DB_NAME'),
'USER': os.environ.get('ANALYTICS_DB_USER'),
'PASSWORD': os.environ.get('ANALYTICS_DB_PASSWORD'),
'HOST': os.environ.get('ANALYTICS_DB_HOST'),
'PORT': '5432',
}
}

# New config.py
from django_cfg import DjangoConfig
from django_cfg.models import DatabaseConfig

class MyConfig(DjangoConfig):
databases: dict[str, DatabaseConfig] = {
"default": DatabaseConfig(
engine="django.db.backends.postgresql",
name="<from-yaml-config>" # Set via environment/config.yaml,
user="<from-yaml-config>" # Set via environment/config.yaml,
password="<from-yaml-config>" # Set via environment/config.yaml,
host="${DB_HOST:localhost}",
port=5432,
sslmode="require",
),
"analytics": DatabaseConfig(
engine="django.db.backends.postgresql",
name="<from-yaml-config>" # Set via environment/config.yaml,
user="<from-yaml-config>" # Set via environment/config.yaml,
password="<from-yaml-config>" # Set via environment/config.yaml,
host="<from-yaml-config>" # Set via environment/config.yaml,
port=5432,
routing_apps=["analytics", "reports"],
),
}

โš ๏ธ Migration Gotchasโ€‹

1. Custom Middleware Orderโ€‹

# Django-CFG adds its own middleware
# Make sure your custom middleware is compatible

class MyConfig(DjangoConfig):
@property
def middleware(self) -> list:
middleware = super().middleware

# Add your custom middleware in the right position
middleware.insert(0, "myapp.middleware.CustomMiddleware")

return middleware

2. Third-Party App Settingsโ€‹

# Some third-party apps need special settings
# Keep them in settings.py temporarily

# settings.py
from config import config
globals().update(config.get_all_settings())

# Third-party app settings that need special handling
CELERY_BROKER_URL = config.redis_url
CELERY_RESULT_BACKEND = config.redis_url

# TODO: Move to config.py when Django-CFG supports them

3. Static Files in Productionโ€‹

# Make sure static files work in production
class MyConfig(DjangoConfig):
# ... other settings ...

@property
def static_root(self) -> str:
if self.is_production:
return "/var/www/static/"
return super().static_root

๐Ÿงช Testing Your Migrationโ€‹

1. Automated Testingโ€‹

# tests/test_migration.py
from django.test import TestCase
from config import config

class MigrationTest(TestCase):
def test_configuration_valid(self):
"""Test that configuration is valid"""
settings = config.get_all_settings()

# Test required settings
self.assertIn("SECRET_KEY", settings)
self.assertIn("DATABASES", settings)
self.assertIn("INSTALLED_APPS", settings)

def test_database_connection(self):
"""Test database connectivity"""
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
result = cursor.fetchone()
self.assertEqual(result[0], 1)

def test_admin_accessible(self):
"""Test admin interface"""
response = self.client.get("/admin/")
self.assertEqual(response.status_code, 302) # Redirect to login

2. Manual Testing Checklistโ€‹

# โœ… Configuration validation
python manage.py validate_config

# โœ… Database connectivity
python manage.py dbshell

# โœ… Admin interface
python manage.py runserver
# Visit http://localhost:8000/admin/

# โœ… API documentation (if enabled)
# Visit http://localhost:8000/api/docs/

# โœ… Static files
python manage.py collectstatic --dry-run

# โœ… Your custom functionality
python manage.py test

Migration Benefitsโ€‹

After migration, you'll have:

FeatureBeforeAfter
Configuration500+ line settings.pyType-safe config.py
Type SafetyNone100% validated
Admin InterfaceBasic Django adminModern Unfold admin
API DocsManual setupAuto-generated
User ManagementBasic User modelOTP auth + profiles
Background TasksManual Celery setupBuilt-in Django-RQ
Support SystemBuild from scratchReady-to-use
NewsletterThird-party serviceBuilt-in system
Lead ManagementCustom solutionBuilt-in CRM
Environment DetectionManual configurationAutomatic
CLI ToolsBasic Django commandsEnhanced commands
IDE SupportBasicFull IntelliSense

Post-Migration Stepsโ€‹

1. Team Trainingโ€‹

# Show team the new features
python manage.py info
python manage.py --help

# Demo the admin interface
python manage.py runserver
# Visit http://localhost:8000/admin/

2. Documentation Updatesโ€‹

Update your project documentation to reflect Django-CFG patterns:

# Old README
1. Copy settings.py.example to settings.py
2. Edit 50+ settings manually
3. Hope everything works

# New README
1. Copy .env.example to .env
2. Edit 5 environment variables
3. Everything just works!

3. CI/CD Updatesโ€‹

# .github/workflows/django.yml
- name: Validate Configuration
run: python manage.py validate_config --strict

- name: Run Enhanced Tests
run: |
python manage.py test
python manage.py check_settings

๐Ÿ†˜ Troubleshootingโ€‹

Configuration Errorsโ€‹

# Debug configuration issues
python manage.py show_config --debug
python manage.py validate_config --verbose

Import Errorsโ€‹

# If you get import errors, check your PYTHONPATH
import sys
sys.path.insert(0, '/path/to/your/project')

Database Issuesโ€‹

# Check database configuration
python manage.py dbshell
python manage.py migrate --dry-run

See Alsoโ€‹

Migration & Setupโ€‹

Getting Started:

Migration Resources:

Configurationโ€‹

Core Configuration:

Infrastructure:

Features & Integrationโ€‹

Built-in Apps:

Integrations:

Tools & Deploymentโ€‹

CLI Tools:

Deployment:

Transform your Django project with Django-CFG! ๐ŸŽฏ

TAGS: migration, upgrade, existing-project, gradual-migration, fresh-start DEPENDS_ON: [installation, configuration] USED_BY: [production-config, deployment]