django-model-utils/tests/test_managers/test_manager_class_assignment.py
Benedikt Willi f09ea0e472 Fix compatibility issues with django-modeltranslation by modifying manager mixins
- Added a new class `_GenericMixin` to serve as a runtime placeholder for `Generic[ModelT]`. This change prevents `TypeError` during `__class__` assignments, which was an issue when mixins inherited from `Generic[T]` at runtime.
- All manager mixins have been updated to inherit from `_GenericMixin` instead of `Generic[ModelT]`. This ensures compatibility with `django-modeltranslation`.
- Introduced regressions tests to confirm that the manager instances support `__class__` reassignment without issues. Tests were added for `SoftDeletableManager`, `InheritanceManager`, `QueryManager`, and `JoinManager`.

Closes GH-#636.
2025-12-15 11:38:33 +01:00

66 lines
2.1 KiB
Python

from __future__ import annotations
from django.db import models
from django.test import SimpleTestCase
from model_utils.managers import (
InheritanceManager,
JoinManager,
QueryManager,
SoftDeletableManager,
)
class ManagerClassAssignmentTests(SimpleTestCase):
"""
Tests for manager __class__ assignment compatibility.
This is a regression test for GitHub issue #636 where manager mixins
inheriting from Generic[T] at runtime were incompatible with
django-modeltranslation due to Python's __class__ assignment restrictions.
The fix moves Generic[T] inheritance behind TYPE_CHECKING so it's only
used for static type checking, not at runtime.
See: https://github.com/jazzband/django-model-utils/issues/636
"""
def test_softdeletable_manager_class_can_be_reassigned(self) -> None:
"""SoftDeletableManager instances support __class__ reassignment."""
manager = SoftDeletableManager()
class PatchedManager(SoftDeletableManager):
pass
manager.__class__ = PatchedManager
self.assertIsInstance(manager, PatchedManager)
def test_inheritance_manager_class_can_be_reassigned(self) -> None:
"""InheritanceManager instances support __class__ reassignment."""
manager = InheritanceManager()
class PatchedManager(InheritanceManager):
pass
manager.__class__ = PatchedManager
self.assertIsInstance(manager, PatchedManager)
def test_query_manager_class_can_be_reassigned(self) -> None:
"""QueryManager instances support __class__ reassignment."""
manager = QueryManager(is_active=True)
class PatchedManager(models.Manager):
pass
manager.__class__ = PatchedManager
self.assertIsInstance(manager, PatchedManager)
def test_join_manager_class_can_be_reassigned(self) -> None:
"""JoinManager instances support __class__ reassignment."""
manager = JoinManager()
class PatchedManager(models.Manager):
pass
manager.__class__ = PatchedManager
self.assertIsInstance(manager, PatchedManager)