Skip to 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]