===================================================== Django Development Requirements ===================================================== **AWX Codebase Best Practices** :Version: 1.0 :Date: September 2025 :Based on: AWX Enterprise Django Application Analysis :Generated by: Claude Code AI ---- .. contents:: Table of Contents :depth: 3 :local: ---- 1. Project Structure ==================== 1.1 Modular Application Architecture ------------------------------------ **REQUIRED**: Organize Django project with clear separation of concerns:: awx/ ├── __init__.py # Version management and environment detection ├── main/ # Core business logic and models ├── api/ # REST API layer (Django REST Framework) ├── ui/ # Frontend integration ├── conf/ # Configuration management ├── settings/ # Environment-specific settings ├── templates/ # Django templates └── static/ # Static assets **Requirements**: - Each functional area must have its own Django app - Use descriptive app names that reflect business domains - Separate API logic from core business logic 1.2 Pre-Management Command Code -------------------------------- This section describes the code that runs before every management command. AWX persistent services (i.e. wsrelay, heartbeat, dispatcher) all have management commands as entry points. So if you want to write a new persistent service, make a management command. System jobs are implemented as management commands too. **REQUIRED**: Implement custom Django management integration: .. code-block:: python # awx/__init__.py def manage(): """Custom management function with environment preparation""" prepare_env() from django.core.management import execute_from_command_line # Version validation for production if not MODE == 'development': validate_production_requirements() execute_from_command_line(sys.argv) **Requirements**: - Environment detection (development/production modes) - Production deployment validation - Custom version checking mechanisms - Database version compatibility checks ---- 2. Settings Management ====================== 2.1 Environment-Based Settings Architecture ------------------------------------------- **REQUIRED**: Use ``django-split-settings`` for modular configuration:: # settings/defaults.py - Base configuration # settings/development.py - Development overrides # settings/production.py - Production security settings # settings/testing.py - Test-specific configuration **Settings Pattern**: .. code-block:: python # development.py from .defaults import * from split_settings.tools import optional, include DEBUG = True ALLOWED_HOSTS = ['*'] # Include optional local settings include(optional('local_settings.py')) 2.2 Sourcing config from files ------------------------------- **REQUIRED**: Sourcing config from multiple files (in a directory) on disk: .. code-block:: python # External settings loading EXTERNAL_SETTINGS = os.environ.get('AWX_SETTINGS_FILE') if EXTERNAL_SETTINGS: include(EXTERNAL_SETTINGS, scope=locals()) 3. URL Patterns and Routing ============================ 3.1 Modular URL Architecture ----------------------------- **REQUIRED**: Implement hierarchical URL organization with namespacing: .. code-block:: python # urls.py def get_urlpatterns(prefix=None): """Dynamic URL pattern generation with prefix support""" if not prefix: prefix = '/' else: prefix = f'/{prefix}/' return [ path(f'api{prefix}', include('awx.api.urls', namespace='api')), path(f'ui{prefix}', include('awx.ui.urls', namespace='ui')), ] urlpatterns = get_urlpatterns() 3.2 Environment-Specific URL Inclusion -------------------------------------- **REQUIRED**: Conditional URL patterns based on environment: This example allows the Django debug toolbar to work. .. code-block:: python # Development-only URLs if settings.DEBUG: try: import debug_toolbar urlpatterns += [path('__debug__/', include(debug_toolbar.urls))] except ImportError: pass **OPTIONAL**: If you want to include your own debug logic and endpoints: .. code-block:: python if MODE == 'development': # Only include these if we are in the development environment from awx.api.swagger import schema_view from awx.api.urls.debug import urls as debug_urls urlpatterns += [re_path(r'^debug/', include(debug_urls))] urlpatterns += [ re_path(r'^swagger(?P\.json|\.yaml)/$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] **Requirements**: - Use Django's ``include()`` for modular organization - Implement URL namespacing for API versioning - Support dynamic URL prefix configuration - Separate URL patterns by functional area ---- 4. Model Design =============== 4.1 Abstract Base Models ------------------------ **REQUIRED**: Use abstract base models for common functionality: .. code-block:: python # models/base.py class BaseModel(models.Model): """Common fields and methods for all models""" created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: abstract = True class AuditableModel(BaseModel): """Models requiring audit trail""" created_by = models.ForeignKey(User, on_delete=models.CASCADE) class Meta: abstract = True 4.2 Mixin-Based Architecture ---------------------------- **REQUIRED**: Implement reusable model behaviors through mixins: .. code-block:: python # models/mixins.py class ResourceMixin(models.Model): """Common resource management functionality""" class Meta: abstract = True class ExecutionEnvironmentMixin(models.Model): """Execution environment configuration""" class Meta: abstract = True 4.3 Model Organization ---------------------- **REQUIRED**: Organize models by domain functionality:: models/ ├── __init__.py ├── base.py # Abstract base models ├── mixins.py # Reusable model behaviors ├── inventory.py # Inventory-related models ├── jobs.py # Job execution models ├── credential.py # Credential management └── organization.py # Organization models **Requirements**: - One file per logical domain until the domain gets too big, create a folder for it instead. In the past, credentials were broken out into logical domains until they were moved out of AWX, then they were collapsed back down to a single file. - Use consistent naming conventions - Implement comprehensive model validation - Custom managers for complex queries ---- 5. REST API Development ======================= 5.1 Custom Authentication Classes ---------------------------------- The recommended best practice is to log all of the terminal (return) paths of authentication, not just the successful ones. **REQUIRED**: Implement domain-specific authentication with logging: .. code-block:: python # api/authentication.py class LoggedBasicAuthentication(authentication.BasicAuthentication): """Basic authentication with request logging""" def authenticate(self, request): if not settings.AUTH_BASIC_ENABLED: return ret = super().authenticate(request) if ret: username = ret[0].username if ret[0] else '' logger.info( f"User {username} performed {request.method} " f"to {request.path} through the API" ) return ret 5.2 Custom Permission Classes ----------------------------- **REQUIRED**: Implement comprehensive permission checking: .. code-block:: python # api/permissions.py class ModelAccessPermission(permissions.BasePermission): """Model-based access control with hierarchy support""" def has_permission(self, request, view): if hasattr(view, 'parent_model'): parent_obj = view.get_parent_object() return check_user_access( request.user, view.parent_model, 'read', parent_obj ) return True **Requirements**: - Multiple authentication methods (JWT, Session, Basic) - Custom pagination, renderers, and metadata classes - Comprehensive API exception handling - Resource-based URL organization - Logging for authentication events ---- 6. Security Requirements ======================== 6.1 Production Security Settings -------------------------------- **REQUIRED**: Enforce secure defaults for production: .. code-block:: python # settings/production.py DEBUG = False SECRET_KEY = None # Force explicit configuration ALLOWED_HOSTS = [] # Must be explicitly set # Session security SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' SESSION_COOKIE_AGE = 1800 # CSRF protection CSRF_COOKIE_SECURE = True CSRF_COOKIE_HTTPONLY = True CSRF_TRUSTED_ORIGINS = [] 6.2 Django SECRET_KEY loading ------------------------------ **REQUIRED**: Implement Django SECRET_KEY loading: .. code-block:: python # Secret key from external file SECRET_KEY_FILE = os.environ.get('SECRET_KEY_FILE', '/etc/awx/SECRET_KEY') if os.path.exists(SECRET_KEY_FILE): with open(SECRET_KEY_FILE, 'rb') as f: SECRET_KEY = f.read().strip().decode() else: if not DEBUG: raise ImproperlyConfigured("SECRET_KEY must be configured in production") For more detail, refer to the `Django documentation `_. 6.3 Proxy and Network Security ------------------------------ **REQUIRED**: Configure reverse proxy security: .. code-block:: python # Proxy configuration REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST'] PROXY_IP_ALLOWED_LIST = [] USE_X_FORWARDED_HOST = True USE_X_FORWARDED_PORT = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') **Requirements**: - External secret file management - Secure cookie configuration - CSRF protection with trusted origins - Proxy header validation - Force HTTPS in production ---- 7. Database Management ====================== 7.1 Advanced Database Configuration ----------------------------------- **REQUIRED**: Robust database connections for production: .. code-block:: python # Database configuration with connection tuning DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DATABASE_NAME', 'awx'), 'ATOMIC_REQUESTS': True, 'CONN_MAX_AGE': 0, 'OPTIONS': { 'keepalives': 1, 'keepalives_idle': 5, 'keepalives_interval': 5, 'keepalives_count': 5, }, } } 7.2 Database Version Validation ------------------------------- **REQUIRED**: Implement database compatibility checking: .. code-block:: python # PostgreSQL version enforcement def validate_database_version(): from django.db import connection if (connection.pg_version // 10000) < 12: raise ImproperlyConfigured( "PostgreSQL version 12 or higher is required" ) 7.3 Migration Management ------------------------ **REQUIRED**: Structured migration organization :: migrations/ ├── 0001_initial.py ├── 0002_squashed_v300_release.py ├── 0003_squashed_v300_v303_updates.py └── _migration_utils.py **Requirements**: It is best practice to not to re-write migrations. If possible, include a reverse migration, especially for data migrations to make testing easier. ---- 8. Testing Standards ==================== 8.1 Pytest Configuration ------------------------- **REQUIRED**: Comprehensive test setup with optimization: .. code-block:: ini # pytest.ini [pytest] DJANGO_SETTINGS_MODULE = awx.main.tests.settings_for_test python_files = *.py addopts = --reuse-db --nomigrations --tb=native markers = ac: access control test survey: tests related to survey feature inventory_import: tests of code used by inventory import command integration: integration tests requiring external services 8.2 Test Settings Module ------------------------- **REQUIRED**: Dedicated test configuration: .. code-block:: python # settings/testing.py from .defaults import * # Fast test database DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3' DATABASES['default']['NAME'] = ':memory:' # Disable migrations for speed class DisableMigrations: def __contains__(self, item): return True def __getitem__(self, item): return None MIGRATION_MODULES = DisableMigrations() 8.3 Coverage Requirements ------------------------- **REQUIRED**: Enforce comprehensive test coverage: .. code-block:: python # Coverage targets COVERAGE_TARGETS = { 'project_overall': 75, 'library_code': 75, 'test_code': 95, 'new_patches': 100, 'type_checking': 100, } **Requirements**: - Database reuse for faster execution - Skip migrations in tests - Custom test markers for categorization - Dedicated test settings module - Comprehensive warning filters ---- 9. Application Configuration ============================= 9.1 Advanced AppConfig Implementation -------------------------------------- **REQUIRED**: Custom application configuration with initialization: .. code-block:: python # apps.py class MainConfig(AppConfig): name = 'awx.main' verbose_name = _('Main') default_auto_field = 'django.db.models.AutoField' def ready(self): super().ready() # Feature loading with environment checks if not os.environ.get('AWX_SKIP_FEATURES', None): self.load_credential_types() self.load_inventory_plugins() self.load_named_urls() # Signal registration self.register_signals() def load_credential_types(self): """Load credential type definitions""" pass def register_signals(self): """Register Django signals""" pass **Requirements**: - Custom AppConfig for complex initialization - Feature loading in ``ready()`` method - Environment-based feature toggling - Plugin system integration - Signal registration ---- 10. Middleware Implementation ============================= 10.1 Custom Middleware for Enterprise Features ---------------------------------------------- **REQUIRED**: Implement domain-specific middleware: .. code-block:: python # middleware.py class SettingsCacheMiddleware(MiddlewareMixin): """Clear settings cache on each request""" def process_request(self, request): from django.conf import settings if hasattr(settings, '_awx_conf_memoizedcache'): settings._awx_conf_memoizedcache.clear() class TimingMiddleware(threading.local, MiddlewareMixin): """Request timing and performance monitoring""" def process_request(self, request): self.start_time = time.time() def process_response(self, request, response): if hasattr(self, 'start_time'): duration = time.time() - self.start_time response['X-Response-Time'] = f"{duration:.3f}s" return response **Requirements**: - Settings cache management middleware - Performance monitoring middleware - Thread-local storage for request data - Conditional middleware activation ---- 11. Deployment Patterns ======================== 11.1 Production-Ready ASGI/WSGI Configuration --------------------------------------------- **REQUIRED**: Proper application server setup: .. code-block:: python # asgi.py import os import django from channels.routing import get_default_application from awx import prepare_env prepare_env() django.setup() application = get_default_application() # wsgi.py import os from django.core.wsgi import get_wsgi_application from awx import prepare_env prepare_env() application = get_wsgi_application() ---- Compliance Checklist ===================== Development Standards --------------------- .. list-table:: :header-rows: 1 :widths: 50 10 * - Requirement - Status * - Modular app architecture implemented - ☐ * - Environment-based settings configured - ☐ * - Custom authentication and permissions - ☐ * - Comprehensive test coverage (>75%) - ☐ * - Security settings enforced - ☐ * - Database optimization configured - ☐ * - Static files properly organized - ☐ * - Custom middleware implemented - ☐ Production Readiness -------------------- .. list-table:: :header-rows: 1 :widths: 50 10 * - Requirement - Status * - External secret management - ☐ * - Database version validation - ☐ * - Version deployment verification - ☐ * - Performance monitoring - ☐ * - Security headers configured - ☐ * - HTTPS enforcement - ☐ * - Proper logging setup - ☐ * - Error handling and monitoring - ☐ Code Quality ------------ .. list-table:: :header-rows: 1 :widths: 50 10 * - Requirement - Status * - Abstract base models used - ☐ * - Mixin-based architecture - ☐ * - Custom management commands - ☐ * - Plugin system support - ☐ * - Signal registration - ☐ * - Migration organization - ☐ * - API documentation - ☐ * - Type hints and validation - ☐ ---- References ========== - **Django Documentation**: https://docs.djangoproject.com/ - **Django REST Framework**: https://www.django-rest-framework.org/ - **Django Split Settings**: https://github.com/sobolevn/django-split-settings - **AWX Source Code**: https://github.com/ansible/awx ---- | **Document Maintainer**: Development Team | **Last Updated**: September 2025 | **Review Schedule**: Quarterly