Skip to content

Django 5.2 Setup and Configuration

Overview

Django 5.2 setup with modern best practices, based on current AzmX technology stack analysis.

Core Dependencies

From requirements.txt analysis:

Django==5.2
django-ninja==1.3.0          # API framework
jinja2==3.1.6                # Template engine
gunicorn==23.0.0              # WSGI server
dj-database-url==1.2.0        # Database URL parsing
psycopg2-binary==2.9.5        # PostgreSQL adapter

Project Structure

project_name/
├── manage.py
├── requirements.txt
├── .env
├── project_name/
│   ├── __init__.py
│   ├── settings/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── development.py
│   │   ├── staging.py
│   │   └── production.py
│   ├── urls.py
│   └── wsgi.py
├── apps/
│   ├── __init__.py
│   ├── core/
│   ├── users/
│   └── api/
└── static/

Settings Configuration

Base Settings (settings/base.py)

import os
from pathlib import Path
import dj_database_url

BASE_DIR = Path(__file__).resolve().parent.parent.parent

# Security
SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = False
ALLOWED_HOSTS = []

# Application definition
DJANGO_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

THIRD_PARTY_APPS = [
    'ninja',
    'storages',
]

LOCAL_APPS = [
    'apps.core',
    'apps.users',
    'apps.api',
]

INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'project_name.urls'

# Database - Django 5.1+ Native Pooling
DATABASES = {
    'default': dj_database_url.config(
        default=os.getenv('DATABASE_URL'),
        conn_max_age=0,  # Required for pooling
        conn_health_checks=True,
    )
}

# Enable connection pooling if supported
if 'postgresql' in DATABASES['default']['ENGINE']:
    DATABASES['default']['OPTIONS'] = {
        'pool': True,
    }

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# Static files configuration
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Development Settings (settings/development.py)

from .base import *

DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME', 'project_dev'),
        'USER': os.getenv('DB_USER', 'postgres'),
        'PASSWORD': os.getenv('DB_PASSWORD', 'password'),
        'HOST': os.getenv('DB_HOST', 'localhost'),
        'PORT': os.getenv('DB_PORT', '5433'),  # Test environment port
        'CONN_MAX_AGE': 0,
        'OPTIONS': {
            'pool': True,
        },
    }
}

# Logging
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'INFO',
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

Production Settings (settings/production.py)

from .base import *

DEBUG = False
ALLOWED_HOSTS = [
    '.azmx.sa',
    'your-domain.com',
]

# Security settings
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'

# Database with environment-specific port
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME'),
        'USER': os.getenv('DB_USER'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST', 'localhost'),
        'PORT': os.getenv('DB_PORT', '5434'),  # Production port
        'CONN_MAX_AGE': 0,
        'OPTIONS': {
            'pool': True,
        },
    }
}

# Static files (DigitalOcean Spaces)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
AWS_S3_ENDPOINT_URL = 'https://nyc3.digitaloceanspaces.com'
AWS_DEFAULT_ACL = 'public-read'

Django Ninja API Setup

API Configuration (apps/api/api.py)

from ninja import NinjaAPI
from ninja.security import HttpBearer
from django.http import HttpRequest

api = NinjaAPI(
    title="AzmX API",
    version="1.0.0",
    description="AzmX Application API",
)

class AuthBearer(HttpBearer):
    def authenticate(self, request: HttpRequest, token: str):
        # Implement your authentication logic
        if token == "valid_token":
            return token
        return None

# Include routers
from .routers import auth, users, core

api.add_router("/auth/", auth.router)
api.add_router("/users/", users.router, auth=AuthBearer())
api.add_router("/core/", core.router, auth=AuthBearer())

URL Configuration (project_name/urls.py)

from django.contrib import admin
from django.urls import path
from apps.api.api import api

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', api.urls),
]

Environment Configuration

Environment Variables (.env)

# Django
SECRET_KEY=your-secret-key-here
DJANGO_SETTINGS_MODULE=project_name.settings.development
DEBUG=True

# Database
DATABASE_URL=postgresql://user:password@localhost:5433/db_name
DB_NAME=project_dev
DB_USER=postgres
DB_PASSWORD=password
DB_HOST=localhost
DB_PORT=5433

# DigitalOcean Spaces
USE_SPACES=FALSE
AWS_ACCESS_KEY_ID=your_spaces_key
AWS_SECRET_ACCESS_KEY=your_spaces_secret
AWS_STORAGE_BUCKET_NAME=your_bucket

# Sentry
SENTRY_DSN=https://[email protected]/project-id
ENVIRONMENT=development

Management Commands

Custom Management Command Example

# apps/core/management/commands/setup_dev_data.py
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User

class Command(BaseCommand):
    help = 'Setup development data'

    def handle(self, *args, **options):
        # Create superuser if it doesn't exist
        if not User.objects.filter(is_superuser=True).exists():
            User.objects.create_superuser(
                username='admin',
                email='[email protected]',
                password='admin123'
            )
            self.stdout.write(
                self.style.SUCCESS('Successfully created superuser')
            )

Deployment Configuration

Gunicorn Configuration (gunicorn.conf.py)

bind = "0.0.0.0:8000"
workers = 3
worker_class = "sync"
worker_connections = 1000
max_requests = 1000
max_requests_jitter = 100
timeout = 30
keepalive = 2
preload_app = True

Docker Configuration (Dockerfile)

FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy project
COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "--config", "gunicorn.conf.py", "project_name.wsgi:application"]

Testing Configuration

Test Settings (settings/test.py)

from .base import *

# Use in-memory database for tests
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
    }
}

# Disable migrations for faster tests
class DisableMigrations:
    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None

MIGRATION_MODULES = DisableMigrations()

# Disable logging during tests
LOGGING_CONFIG = None

Performance Optimizations

Database Query Optimization

# Use select_related and prefetch_related
queryset = Model.objects.select_related('foreign_key').prefetch_related('many_to_many')

# Use database functions
from django.db.models import Count, Avg
Model.objects.aggregate(count=Count('id'), average=Avg('value'))

Caching Configuration

# Cache configuration
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': os.getenv('REDIS_URL', 'redis://127.0.0.1:6379/1'),
    }
}

# Session configuration
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

References