Django Modelcluster
django-modelcluster is a Django extension that allows working with 'clusters' of related models as a single unit, independently of the database. It introduces `ParentalKey` and `ClusterableModel` to enable in-memory manipulation of related objects, which is particularly useful for features like previews and revisions in content management systems like Wagtail. The current version is 6.4.1, and it maintains a consistent release schedule, often aligning with Django and Python version support.
Warnings
- breaking In `ClusterForm` (v6.0 and later), child formsets are no longer built by default if neither `formsets` nor `exclude_formsets` is specified in the Meta class. This changes previous behavior where all child relations would automatically get a formset.
- breaking `django-modelcluster` frequently drops support for older Django and Python versions. For example, v6.4 removed Django 3.2 and Python 3.8 support.
- gotcha A `ParentalKey` field must point to a model that inherits from `ClusterableModel`. Failing to do so will result in a Django system check error.
- gotcha Using `related_name='+'` is not allowed on `ParentalKey` fields, as `ParentalKey` requires an accessor name for its internal mechanisms.
- gotcha While `django-modelcluster` provides a `QuerySet`-like API for in-memory child objects, it's a 'fake' QuerySet with limitations. Advanced queryset operations (e.g., complex `order_by` traversals, `distinct()` before v6.3, or raw SQL queries) may not work as expected or are not supported on unsaved instances, particularly in contexts like content previews.
- gotcha For `ParentalManyToManyField`, only the *relationships* between the parent and the related objects are managed in memory. The *related objects themselves* (e.g., `Actor` instances in a `Movie.actors = ParentalManyToManyField(Actor)`) must already exist in the database before they can be associated in memory with the parent.
Install
-
pip install django-modelcluster
Imports
- ClusterableModel
from modelcluster.models import ClusterableModel
- ParentalKey
from modelcluster.fields import ParentalKey
- ParentalManyToManyField
from modelcluster.fields import ParentalManyToManyField
- ClusterForm
from modelcluster.forms import ClusterForm
Quickstart
from django.db import models
from modelcluster.models import ClusterableModel
from modelcluster.fields import ParentalKey
class Band(ClusterableModel):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class BandMember(models.Model):
band = ParentalKey(
'Band',
related_name='members',
on_delete=models.CASCADE
)
name = models.CharField(max_length=255)
def __str__(self):
return self.name
# Example usage (in a Django shell or view):
beatles = Band(name='The Beatles')
# Related objects can be assigned to the in-memory 'members' attribute
beatles.members = [
BandMember(name='John Lennon'),
BandMember(name='Paul McCartney'),
BandMember(name='George Harrison'),
BandMember(name='Ringo Starr'),
]
# Accessing in-memory members (behaves like a QuerySet subset)
print([member.name for member in beatles.members.all()])
# Output: ['John Lennon', 'Paul McCartney', 'George Harrison', 'Ringo Starr']
# To save the cluster and its members to the database:
# beatles.save()
# This would also save all associated BandMember instances via ParentalKey