Skip to content

Conversation

@Hopiu
Copy link
Contributor

@Hopiu Hopiu commented Dec 15, 2025

Problem

When using django-model-utils together with django-modeltranslation, registering a model that uses SoftDeletableModel (or other models using manager mixins) causes a TypeError during app initialization:

This occurs because django-modeltranslation patches manager classes by reassigning manager.__class__ to a dynamically created subclass. Python's __class__ assignment has strict layout compatibility requirements, and the Generic[ModelT] base class in our manager mixins causes a layout mismatch.

Fixes #636

Solution

Move the Generic[ModelT] inheritance behind TYPE_CHECKING so it's only present during static type analysis, not at runtime. At runtime, a simple placeholder class _GenericMixin is used instead.

Commandments

  • Write PEP8 compliant code.
  • Cover it with tests.
  • Update CHANGES.rst file to describe the changes, and quote according issue with GH-<issue_number>.
  • Pay attention to backward compatibility, or if it breaks it, explain why.

…nager 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-jazzband#636.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeError: __class__ assignment: 'NewMultilingualManager' object layout differs from 'SoftDeletableManager'

1 participant