Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions JAZZMIN_FIX_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,38 @@
## Problem
Django 6.0 introduced a breaking change where `format_html()` now requires at least one argument (args or kwargs). The jazzmin package (v3.0.1) uses `format_html(html_str)` which causes a `TypeError: args or kwargs must be provided` error when accessing admin list views with pagination.

### Error Example
```
TypeError at /admin/core/booking/
args or kwargs must be provided.

Exception Location: /opt/Finoa/.venv/lib/python3.12/site-packages/django/utils/html.py, line 137, in format_html
```

## Solution
This fix patches the jazzmin package's `jazzmin_paginator_number` template tag to use `mark_safe()` instead of `format_html()` for Django 6.0 compatibility.

### Implementation

1. **Automated Patch Script** (`fix_jazzmin.sh`):
- Automatically locates the jazzmin package installation
- Patches line 256 in `jazzmin/templatetags/jazzmin.py`
- Replaces `return format_html(html_str)` with `return mark_safe(html_str)`
**Automated Patch Script** (`fix_jazzmin.sh`):
- Automatically locates the jazzmin package installation
- Patches line 256 in `jazzmin/templatetags/jazzmin.py`
- Replaces `return format_html(html_str)` with `return mark_safe(html_str)`

2. **Usage**:
```bash
# Run after installing requirements.txt
./fix_jazzmin.sh
```
### Usage
```bash
# Run after installing requirements.txt
cd /path/to/Finoa
pip install -r requirements.txt
./fix_jazzmin.sh
python manage.py runserver
```

## Why This Works
- `mark_safe()` marks a string as safe for HTML output without requiring additional arguments
- The HTML string is already properly formatted by the template tag
- No security impact since the string is built from trusted sources (Django's own ChangeList object)

## Files Changed
- `fix_jazzmin.sh` - New patch script
- `finoa/settings.py` - Updated INSTALLED_APPS order (core before jazzmin) for template tag override precedence
- `core/templatetags/__init__.py` - Template tags package init
- `core/templatetags/jazzmin.py` - Custom jazzmin template tag override (fallback solution)
- `core/apps.py` - Reverted to original (monkey patch approach removed)
- The patch is applied directly to the installed jazzmin package

## Deployment
Run the patch script as part of your deployment process:
Expand All @@ -39,10 +44,22 @@ pip install -r requirements.txt
python manage.py runserver
```

**Note**: The patch needs to be reapplied after each time you reinstall or upgrade the jazzmin package.

## Alternative Solutions Considered
1. ✗ Monkey patching in `CoreConfig.ready()` - Doesn't work because template tags are loaded before AppConfig.ready()
2. ✗ Custom template tag override - Doesn't work reliably due to Python module caching
2. ✗ Custom template tag override - Doesn't work because Django loads the first matching template tag library name from INSTALLED_APPS, and both modules use the same name "jazzmin"
3. ✓ Direct file patch via shell script - Works reliably and is easy to integrate into deployment

## Technical Details
The issue is in `/path/to/site-packages/jazzmin/templatetags/jazzmin.py` at line 256:
```python
# Before (causes error in Django 6.0):
return format_html(html_str)

# After (works in Django 6.0):
return mark_safe(html_str)
```

## Note
This is a temporary fix until jazzmin releases a Django 6.0 compatible version. Monitor the jazzmin GitHub repository for official updates.
This is a temporary fix until jazzmin releases a Django 6.0 compatible version. Monitor the [jazzmin GitHub repository](https://github.com/farridav/django-jazzmin) for official updates.
84 changes: 84 additions & 0 deletions core/tests_jazzmin_templatetag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""
Tests for Django 6.0 compatibility fixes in core.templatetags.jazzmin
"""
from django.contrib.admin.views.main import ChangeList
from django.test import TestCase, RequestFactory
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
from django.contrib.admin import ModelAdmin

from core.templatetags.jazzmin import jazzmin_paginator_number


class JazzminPaginatorNumberTestCase(TestCase):
"""Test the jazzmin_paginator_number template tag for Django 6.0 compatibility."""

def setUp(self):
"""Set up test fixtures."""
self.factory = RequestFactory()
self.site = AdminSite()

def test_jazzmin_paginator_number_returns_safe_html(self):
"""Test that jazzmin_paginator_number returns SafeText without errors."""
# Create a mock request
request = self.factory.get('/admin/auth/user/')
request.user = User(username='admin', is_staff=True, is_superuser=True)

# Create a ModelAdmin instance
model_admin = ModelAdmin(User, self.site)

# Create a ChangeList - this would normally be done by Django admin
changelist = ChangeList(
request=request,
model=User,
list_display=['username'],
list_display_links=['username'],
list_filter=[],
date_hierarchy=None,
search_fields=[],
list_select_related=[],
list_per_page=100,
list_max_show_all=200,
list_editable=[],
model_admin=model_admin,
sortable_by=[],
search_help_text=None,
)

# Test the template tag with different page numbers
# This should not raise "TypeError: args or kwargs must be provided"
try:
result = jazzmin_paginator_number(changelist, 1)
self.assertIsNotNone(result)
self.assertIn('page-item', str(result))
except TypeError as e:
if "args or kwargs must be provided" in str(e):
self.fail("Template tag still uses format_html incorrectly")
raise

def test_jazzmin_paginator_number_start_page(self):
"""Test pagination rendering for the first page."""
request = self.factory.get('/admin/auth/user/')
request.user = User(username='admin', is_staff=True, is_superuser=True)

model_admin = ModelAdmin(User, self.site)
changelist = ChangeList(
request=request,
model=User,
list_display=['username'],
list_display_links=['username'],
list_filter=[],
date_hierarchy=None,
search_fields=[],
list_select_related=[],
list_per_page=100,
list_max_show_all=200,
list_editable=[],
model_admin=model_admin,
sortable_by=[],
search_help_text=None,
)

result = jazzmin_paginator_number(changelist, 1)
self.assertIn('previous', str(result))
self.assertIn('«', str(result))