--- name: django-6-upgrade description: "⚠️ DRAFT/SPEKULATIV - Django 6.0 ist noch nicht released! Diese Dokumentation basiert auf erwarteten Features. Für aktuelle Upgrades (4.2 → 5.2) bitte offizielle Django Docs verwenden." argument-hint: [--check-only | --full-upgrade] allowed-tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch --- > **⚠️ DRAFT - NICHT PRODUKTIONSREIF** > > Django 6.0 ist noch nicht released (Stand: Februar 2026). > Diese Dokumentation basiert auf Spekulationen und erwarteten Features. > Features wie "Background Tasks Framework", "Template Partials", "CSP Middleware" sind NICHT bestätigt. > > **Für aktuelle Upgrades bitte offizielle Django Dokumentation verwenden:** > - Django 4.2 → 5.0: https://docs.djangoproject.com/en/5.0/releases/5.0/ > - Django 5.0 → 5.1: https://docs.djangoproject.com/en/5.1/releases/5.1/ > - Django 5.1 → 5.2: https://docs.djangoproject.com/en/5.2/releases/5.2/ # Django 5.2 → 6.0 Upgrade Guide (DRAFT/SPEKULATIV) Comprehensive guide for upgrading Django projects from 5.2 LTS to 6.0, covering breaking changes, removed deprecations, and new features like background tasks, template partials, and CSP support. ## When to Use - Upgrading a Django 5.2 project to Django 6.0 - Checking compatibility before upgrading - Fixing deprecation warnings from Django 5.x - Adopting new Django 6.0 features (CSP, template partials, background tasks) ## Prerequisites - **Python 3.12+** required (Django 6.0 drops Python 3.10/3.11 support) - Django 5.2 project with passing tests - All third-party packages compatible with Django 6.0 ## Upgrade Checklist ### Phase 1: Pre-Upgrade Preparation ```bash # 1. Check Python version (must be 3.12+) python --version # 2. Run deprecation warnings check python -Wd manage.py check python -Wd manage.py test # 3. Run django-upgrade tool (automatic fixes) pip install django-upgrade django-upgrade --target-version 6.0 **/*.py ``` ### Phase 2: Breaking Changes #### 1. Python Version Requirement ```python # pyproject.toml or setup.py # BEFORE python_requires = ">=3.10" # AFTER python_requires = ">=3.12" ``` #### 2. DEFAULT_AUTO_FIELD Change Django 6.0 defaults to `BigAutoField`. If your project already sets this, you can remove it: ```python # settings.py # REMOVE this line if it's set to BigAutoField (now the default) # DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # KEEP if using a different field type DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' # Keep if intentional ``` **WARNING**: Removing `DEFAULT_AUTO_FIELD` when set to `AutoField` will cause migrations! #### 3. Database Backend Changes ```python # BEFORE (Django 5.2) class MyDatabaseOperations(DatabaseOperations): def return_insert_columns(self, fields): ... def fetch_returned_insert_rows(self, cursor): ... def fetch_returned_insert_columns(self, cursor): ... # AFTER (Django 6.0) class MyDatabaseOperations(DatabaseOperations): def returning_columns(self, fields): # Renamed ... def fetch_returned_rows(self, cursor): # Renamed ... # fetch_returned_insert_columns is REMOVED ``` #### 4. Email API Changes ```python # BEFORE (Django 5.2) from django.core.mail import BadHeaderError, SafeMIMEText, SafeMIMEMultipart from django.core.mail.message import sanitize_address, forbid_multi_line_headers try: send_mail(subject, message, from_email, [to_email]) except BadHeaderError: pass # AFTER (Django 6.0) # BadHeaderError → ValueError # SafeMIMEText/SafeMIMEMultipart → Use Python's email.mime classes directly # sanitize_address/forbid_multi_line_headers → Removed try: send_mail(subject, message, from_email, [to_email]) except ValueError: # Replaces BadHeaderError pass ``` #### 5. ADMINS/MANAGERS Settings ```python # BEFORE (Django 5.2) - Deprecated tuple format ADMINS = [ ('Admin Name', 'admin@example.com'), ('Another Admin', 'another@example.com'), ] # AFTER (Django 6.0) - Email strings only ADMINS = [ 'admin@example.com', 'another@example.com', ] # Same for MANAGERS MANAGERS = [ 'manager@example.com', ] ``` #### 6. BaseConstraint Positional Arguments ```python # BEFORE (Django 5.2) class MyConstraint(BaseConstraint): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # AFTER (Django 6.0) - Positional args removed class MyConstraint(BaseConstraint): def __init__(self, *, name, violation_error_code=None, violation_error_message=None): super().__init__( name=name, violation_error_code=violation_error_code, violation_error_message=violation_error_message, ) ``` #### 7. ModelAdmin.lookup_allowed() Signature ```python # BEFORE (Django 5.2) class MyModelAdmin(admin.ModelAdmin): def lookup_allowed(self, lookup, value): return super().lookup_allowed(lookup, value) # AFTER (Django 6.0) - request is required class MyModelAdmin(admin.ModelAdmin): def lookup_allowed(self, lookup, value, request): # request added return super().lookup_allowed(lookup, value, request) ``` #### 8. Prefetch QuerySet Method ```python # BEFORE (Django 5.2) class MyManager(Manager): def get_prefetch_queryset(self, instances, queryset=None): ... # AFTER (Django 6.0) class MyManager(Manager): def get_prefetch_querysets(self, instances, querysets=None): # Plural ... ``` #### 9. Form Renderer Changes ```python # BEFORE (Django 5.2) - Transitional renderers from django.forms.renderers import DjangoDivFormRenderer, Jinja2DivFormRenderer # AFTER (Django 6.0) - Removed, use standard renderers from django.forms.renderers import DjangoTemplates, Jinja2 # Or the new default which uses div-based rendering ``` #### 10. StringAgg Import Location ```python # BEFORE (Django 5.2) - PostgreSQL only from django.contrib.postgres.aggregates import StringAgg # AFTER (Django 6.0) - Available for all databases from django.db.models import StringAgg # Note: Delimiter must be wrapped in Value() for string literals from django.db.models import Value result = MyModel.objects.aggregate( names=StringAgg('name', delimiter=Value(', ')) ) ``` ### Phase 3: New Features to Adopt #### 1. Content Security Policy (CSP) ```python # settings.py MIDDLEWARE = [ ... 'django.middleware.security.ContentSecurityPolicyMiddleware', # Add ... ] # CSP Configuration SECURE_CSP = { 'default-src': ["'self'"], 'script-src': ["'self'", "'nonce'"], # 'nonce' enables nonce support 'style-src': ["'self'", "'unsafe-inline'"], 'img-src': ["'self'", 'data:', 'https:'], 'font-src': ["'self'"], 'connect-src': ["'self'"], 'frame-ancestors': ["'none'"], } # Report-only mode for testing SECURE_CSP_REPORT_ONLY = { 'default-src': ["'self'"], 'report-uri': '/csp-report/', } # templates/base.html TEMPLATES = [ { ... 'OPTIONS': { 'context_processors': [ ... 'django.template.context_processors.csp', # Add for nonce support ], }, }, ] ``` ```html ``` #### 2. Template Partials ```html {% partialdef card %}

{{ title }}

{{ content }}

{% endpartialdef %} {% partialdef button %} {% endpartialdef %} {% extends "base.html" %} {% load partials %} {% block content %} {% partial "components.html#card" title="Hello" content="World" %} {% partial "components.html#button" text="Click me" variant="success" %} {% partialdef alert %}
{{ message }}
{% endpartialdef %} {% partial alert level="warning" message="This is a warning" %} {% endblock %} ``` #### 3. Background Tasks Framework ```python # myapp/tasks.py from django.tasks import task, TaskResult @task def send_welcome_email(user_id: int) -> TaskResult: """Send welcome email to user.""" from django.contrib.auth import get_user_model from django.core.mail import send_mail User = get_user_model() user = User.objects.get(pk=user_id) send_mail( subject='Welcome!', message=f'Welcome to our site, {user.username}!', from_email='noreply@example.com', recipient_list=[user.email], ) return TaskResult(success=True, result={'user_id': user_id}) @task(priority=10, queue='high-priority') def process_order(order_id: int) -> TaskResult: """Process an order in the background.""" from myapp.models import Order order = Order.objects.get(pk=order_id) order.process() return TaskResult(success=True, result={'order_id': order_id}) # views.py - Enqueue tasks from myapp.tasks import send_welcome_email, process_order def register_user(request): user = User.objects.create_user(...) # Enqueue background task send_welcome_email.enqueue(user.pk) return redirect('home') def checkout(request): order = Order.objects.create(...) # Enqueue with options process_order.enqueue( order.pk, delay=60, # Delay execution by 60 seconds ) return redirect('order-confirmation') ``` ```python # settings.py - Task backend configuration TASKS = { 'BACKEND': 'django.tasks.backends.database.DatabaseBackend', # Or for development: # 'BACKEND': 'django.tasks.backends.immediate.ImmediateBackend', } # For production, you'll need a task runner (not included in Django) # See django-tasks-scheduler or implement your own worker ``` #### 4. Async Pagination ```python # views.py from django.core.paginator import AsyncPaginator async def async_list_view(request): queryset = MyModel.objects.all() paginator = AsyncPaginator(queryset, per_page=25) page_number = request.GET.get('page', 1) page = await paginator.aget_page(page_number) return render(request, 'list.html', {'page': page}) ``` ### Phase 4: Automated Fixes with django-upgrade ```bash # Install django-upgrade pip install django-upgrade # Run on entire project django-upgrade --target-version 6.0 $(find . -name "*.py" -not -path "./.venv/*") # Or with pre-commit # .pre-commit-config.yaml repos: - repo: https://github.com/adamchainz/django-upgrade rev: "1.21.0" hooks: - id: django-upgrade args: [--target-version, "6.0"] ``` **django-upgrade 6.0 Fixers:** 1. `mail_api_kwargs` - Rewrites positional arguments to keyword arguments for mail APIs 2. `default_auto_field` - Removes redundant BigAutoField settings 3. `stringagg` - Moves StringAgg imports and wraps delimiter in Value() 4. `settings_admins_managers` - Converts ADMINS/MANAGERS to string format ### Phase 5: Testing & Verification ```bash # 1. Run full test suite with deprecation warnings python -Wd manage.py test # 2. Check for system issues python manage.py check --deploy # 3. Verify migrations python manage.py makemigrations --check --dry-run # 4. Test CSP in browser # Check browser console for CSP violations # Use Report-Only mode first # 5. Verify background tasks python manage.py shell >>> from myapp.tasks import send_welcome_email >>> result = send_welcome_email.enqueue(1) >>> print(result.status) ``` ## Search Patterns for Common Issues ```python # Find BadHeaderError usage # grep -r "BadHeaderError" --include="*.py" # Find SafeMIMEText/SafeMIMEMultipart # grep -r "SafeMIME" --include="*.py" # Find ADMINS/MANAGERS tuples # grep -r "ADMINS\s*=\s*\[" --include="*.py" -A 3 # Find get_prefetch_queryset # grep -r "get_prefetch_queryset" --include="*.py" # Find lookup_allowed without request # grep -r "def lookup_allowed" --include="*.py" # Find StringAgg from postgres # grep -r "from django.contrib.postgres.aggregates import.*StringAgg" --include="*.py" # Find DjangoDivFormRenderer # grep -r "DjangoDivFormRenderer\|Jinja2DivFormRenderer" --include="*.py" ``` ## Third-Party Package Compatibility Check these common packages for Django 6.0 compatibility: | Package | Status | Notes | |---------|--------|-------| | django-rest-framework | ✅ 3.16+ | Check for DRF-specific changes | | celery | ✅ 5.5+ | Consider migrating to Django Tasks | | django-debug-toolbar | ✅ Check version | | | django-crispy-forms | ✅ 2.x | | | django-allauth | ✅ Check version | | | django-filter | ✅ Check version | | | django-cors-headers | ✅ Check version | | ## Common Pitfalls - **Python version**: Django 6.0 requires Python 3.12+, no exceptions - **DEFAULT_AUTO_FIELD migrations**: Removing this setting can trigger migrations - **Email exceptions**: Replace `BadHeaderError` with `ValueError` - **ADMINS format**: Must be strings, not tuples - **Background Tasks**: Django provides task definition, not task execution (no built-in worker) - **CSP nonce**: Remember to add context processor for nonce support - **Template partials**: New templatetags need `{% load partials %}` ## Rollback Plan If issues arise: ```bash # Pin Django version pip install "Django>=5.2,<6.0" # Or in requirements.txt Django>=5.2,<6.0 ``` Django 5.2 LTS is supported until April 2028. ## Sources - [Django 6.0 Release Notes](https://docs.djangoproject.com/en/6.0/releases/6.0/) - [Django Deprecation Timeline](https://docs.djangoproject.com/en/dev/internals/deprecation/) - [django-upgrade Tool](https://github.com/adamchainz/django-upgrade) - [Django 6.0 Deep Dive - Adam Johnson](https://adamj.eu/tech/2025/12/03/django-whats-new-6.0/)