Skip to main content

Settings Integration

Settings integration is one of the core features of Django SuperApp. It allows each app to define and inject its own configuration into the main project settings automatically.

How Settings Integration Works

When your Django SuperApp project starts, the framework automatically discovers and executes the extend_superapp_settings() function from each app’s settings.py file.

The extend_superapp_settings Function

The core integration function is defined in src/django_superapp/settings.py:9-21:
def extend_superapp_settings(main_settings, superapp_apps):
    for importer, modname, ispkg in pkgutil.iter_modules(superapp_apps.__path__):
        submodule_name = f"{superapp_apps.__name__}.{modname}.settings"

        try:
            settings_module = importlib.import_module(submodule_name)
        except ModuleNotFoundError as e:
            if f"No module named '{submodule_name}'" in str(e):
                continue
            raise e

        if hasattr(settings_module, "extend_superapp_settings"):
            settings_module.extend_superapp_settings(main_settings)

Integration Flow

Creating App Settings

Each app can define its settings integration by creating a settings.py file with the extend_superapp_settings() function.

Basic Example

From CONVENTIONS.md:14-18:
def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.sample_app']
This minimal example adds the app to Django’s INSTALLED_APPS setting.

The main_settings Parameter

The main_settings parameter is a dictionary containing all of Django’s settings. You can modify any setting by directly accessing and updating the dictionary:
def extend_superapp_settings(main_settings):
    # Add to INSTALLED_APPS
    main_settings['INSTALLED_APPS'] += ['superapp.apps.your_app']
    
    # Add middleware
    main_settings['MIDDLEWARE'] += ['superapp.apps.your_app.middleware.CustomMiddleware']
    
    # Update templates
    main_settings['TEMPLATES'][0]['DIRS'] += [
        'superapp/apps/your_app/templates'
    ]
    
    # Add custom settings
    main_settings['YOUR_APP_CUSTOM_SETTING'] = 'value'

Real-World Examples

Adding INSTALLED_APPS

The most common use case is registering your app with Django:
def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += [
        'superapp.apps.authentication',
    ]

Configuring django-unfold Admin

From CONVENTIONS.md:59-81, apps can configure the admin sidebar navigation:
from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.sample_app']

    main_settings['UNFOLD']['SIDEBAR']['navigation'] = [
        {
            "title": _("Sample App"),
            "icon": "extension",  # Material Icons from Google Fonts
            "items": [
                {
                    "title": lambda request: _("Sample Models"),
                    "icon": "table_rows",
                    "link": reverse_lazy("admin:sample_app_samplemodel_changelist"),
                    "permission": lambda request: request.user.has_perm("sample_app.view_samplemodel"),
                },
            ]
        },
    ]
Icons are from Google Material Icons. The URL pattern name typically follows the format admin:app_modelname_changelist.

Adding Multiple Configuration Items

def extend_superapp_settings(main_settings):
    # Register app
    main_settings['INSTALLED_APPS'] += [
        'rest_framework',
        'superapp.apps.api',
    ]
    
    # Configure REST Framework
    main_settings['REST_FRAMEWORK'] = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.SessionAuthentication',
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 100,
    }
    
    # Add custom API settings
    main_settings['API_VERSION'] = 'v1'
    main_settings['API_RATE_LIMIT'] = '100/hour'

Configuring Middleware

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.monitoring']
    
    # Add monitoring middleware
    main_settings['MIDDLEWARE'] += [
        'superapp.apps.monitoring.middleware.RequestTimingMiddleware',
        'superapp.apps.monitoring.middleware.ErrorTrackingMiddleware',
    ]

Adding Template Directories

import os

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.theme']
    
    # Add app templates directory
    app_templates = os.path.join(
        os.path.dirname(__file__), 
        'templates'
    )
    main_settings['TEMPLATES'][0]['DIRS'].append(app_templates)

Configuring Database Connections

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.analytics']
    
    # Add additional database for analytics
    main_settings['DATABASES']['analytics'] = {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'analytics_db',
        'USER': 'analytics_user',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '5432',
    }

Advanced Patterns

Conditional Configuration

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.debugging']
    
    # Only enable debug toolbar in development
    if main_settings.get('DEBUG', False):
        main_settings['INSTALLED_APPS'] += ['debug_toolbar']
        main_settings['MIDDLEWARE'] += [
            'debug_toolbar.middleware.DebugToolbarMiddleware'
        ]

Extending Existing Settings

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.security']
    
    # Extend existing CORS settings
    cors_origins = main_settings.get('CORS_ALLOWED_ORIGINS', [])
    cors_origins += [
        'https://api.example.com',
        'https://admin.example.com',
    ]
    main_settings['CORS_ALLOWED_ORIGINS'] = cors_origins

Environment-Based Configuration

import os

def extend_superapp_settings(main_settings):
    main_settings['INSTALLED_APPS'] += ['superapp.apps.email']
    
    # Configure email backend based on environment
    if os.getenv('ENVIRONMENT') == 'production':
        main_settings['EMAIL_BACKEND'] = 'django.core.mail.backends.smtp.EmailBackend'
        main_settings['EMAIL_HOST'] = os.getenv('EMAIL_HOST')
    else:
        main_settings['EMAIL_BACKEND'] = 'django.core.mail.backends.console.EmailBackend'

Settings Integration Best Practices

Use += for Lists

Always use += when adding to list settings like INSTALLED_APPS or MIDDLEWARE to preserve existing values.

Check Existing Values

Use main_settings.get() to safely check for existing settings before modifying.

Namespace Custom Settings

Prefix app-specific settings with your app name to avoid conflicts (e.g., YOUR_APP_SETTING).

Document Dependencies

If your settings require third-party packages, document them in requirements.txt.

Common Settings to Modify

Register your app and any required third-party apps.
main_settings['INSTALLED_APPS'] += [
    'rest_framework',
    'superapp.apps.your_app',
]
Add custom middleware for request/response processing.
main_settings['MIDDLEWARE'] += [
    'superapp.apps.your_app.middleware.CustomMiddleware',
]
Configure template directories and context processors.
main_settings['TEMPLATES'][0]['DIRS'] += [
    'superapp/apps/your_app/templates'
]
Configure django-unfold admin interface and sidebar navigation.
main_settings['UNFOLD']['SIDEBAR']['navigation'] = [...]
Configure Django REST Framework settings for APIs.
main_settings['REST_FRAMEWORK'] = {
    'DEFAULT_PERMISSION_CLASSES': [...],
}
Be careful when modifying settings that other apps might also modify. Use list operations like += instead of direct assignment to avoid overwriting other apps’ configurations.

Error Handling

The framework handles missing settings.py files gracefully:
try:
    settings_module = importlib.import_module(submodule_name)
except ModuleNotFoundError as e:
    if f"No module named '{submodule_name}'" in str(e):
        continue  # App doesn't have settings.py - skip it
    raise e  # Other import errors are raised
This means:
  • Apps without settings.py are silently skipped
  • Syntax errors or other import errors will still raise exceptions
  • Apps can have only urls.py without settings.py

Next Steps

URL Integration

Learn how to register app URLs

App System

Understand the complete app structure

Admin Integration

Configure admin sidebar navigation

Build docs developers (and LLMs) love