=====================================================
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<format>\.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 '<none>'
                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 <https://docs.djangoproject.com/en/5.2/ref/settings/#secret-key>`_.

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