{"id":1999,"library":"django-modelcluster","title":"Django Modelcluster","description":"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.","status":"active","version":"6.4.1","language":"python","source_language":"en","source_url":"https://github.com/wagtail/django-modelcluster","tags":["django","orm","models","relationships","formsets","wagtail"],"install":[{"cmd":"pip install django-modelcluster","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core dependency as it's a Django extension.","package":"Django","optional":false},{"reason":"Often used with `ClusterTaggableManager` for tagging functionality in Wagtail contexts. Not strictly required for basic `django-modelcluster` usage.","package":"django-taggit","optional":true}],"imports":[{"wrong":"from modelcluster.models import ClusterableModel","symbol":"ClusterableModel","correct":"from modelcluster.models import ClusterableModel"}],"quickstart":{"code":"from django.db import models\nfrom modelcluster.models import ClusterableModel\nfrom modelcluster.fields import ParentalKey\n\nclass Band(ClusterableModel):\n    name = models.CharField(max_length=255)\n\n    def __str__(self):\n        return self.name\n\nclass BandMember(models.Model):\n    band = ParentalKey(\n        'Band', \n        related_name='members',\n        on_delete=models.CASCADE\n    )\n    name = models.CharField(max_length=255)\n\n    def __str__(self):\n        return self.name\n\n# Example usage (in a Django shell or view):\nbeatles = Band(name='The Beatles')\n# Related objects can be assigned to the in-memory 'members' attribute\nbeatles.members = [\n    BandMember(name='John Lennon'),\n    BandMember(name='Paul McCartney'),\n    BandMember(name='George Harrison'),\n    BandMember(name='Ringo Starr'),\n]\n\n# Accessing in-memory members (behaves like a QuerySet subset)\nprint([member.name for member in beatles.members.all()])\n# Output: ['John Lennon', 'Paul McCartney', 'George Harrison', 'Ringo Starr']\n\n# To save the cluster and its members to the database:\n# beatles.save()\n# This would also save all associated BandMember instances via ParentalKey","lang":"python","description":"This example demonstrates defining a `ClusterableModel` (Band) and a related model (`BandMember`) connected via `ParentalKey`. It shows how to create a cluster of related objects in memory and access them before saving them to the database."},"warnings":[{"fix":"Explicitly define `formsets` or `exclude_formsets` within the `Meta` class of your `ClusterForm` to control which child relations have formsets.","message":"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.","severity":"breaking","affected_versions":">=6.0"},{"fix":"Always check the release notes (`CHANGELOG.txt`) for version compatibility and ensure your `django-modelcluster` version aligns with your Django and Python environment.","message":"`django-modelcluster` frequently drops support for older Django and Python versions. For example, v6.4 removed Django 3.2 and Python 3.8 support.","severity":"breaking","affected_versions":"All versions"},{"fix":"Ensure the model referenced by `ParentalKey` (e.g., the 'Band' in `ParentalKey('Band', ...)`) inherits `modelcluster.models.ClusterableModel`.","message":"A `ParentalKey` field must point to a model that inherits from `ClusterableModel`. Failing to do so will result in a Django system check error.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Provide a meaningful `related_name` for all `ParentalKey` fields, or omit it to let Django infer one.","message":"Using `related_name='+'` is not allowed on `ParentalKey` fields, as `ParentalKey` requires an accessor name for its internal mechanisms.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Be aware of these limitations when querying in-memory relations. For complex logic, ensure the parent model and its children are saved, or adapt your code to work with lists/iterators where full queryset functionality isn't available.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure that any objects intended to be related via `ParentalManyToManyField` are persisted to the database before attempting to establish the in-memory relationship with the parent `ClusterableModel`.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"search_vec":"'6.4.1':60 'align':69 'allow':11 'cluster':14 'clusterablemodel':30 'consist':65 'content':51 'current':57 'databas':25 'django':1,4,8,71,76 'django-modelclust':3 'enabl':32 'extens':9 'featur':45 'formset':80 'in-memori':33 'independ':22 'introduc':27 'like':46,54 'maintain':63 'manag':52 'manipul':36 'memori':35 'model':17,78 'modelclust':2,5 'object':39 'often':68 'orm':77 'parentalkey':28 'particular':42 'preview':47 'python':73 'relat':16,38 'relationship':79 'releas':66 'revis':49 'schedul':67 'singl':20 'support':75 'system':53 'unit':21 'use':43 'version':58,74 'wagtail':55,81 'work':12","created_at":"2026-04-09T18:39:11.697781+00:00","updated_at":"2026-04-16T14:32:21.876211+00:00","problems":{"verify_error":"Traceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n  File \"/tmp/tmprbrhx3cl/venv/lib/python3.12/site-packages/modelcluster/models.py\", line 168, in <module>\n    class ClusterableModel(models.Model):\n  File \"/tmp/tmprbrhx3cl/venv/lib/python3.12/site-packages/django/db/models/ba"},"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"6.5","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"https://github.com/wagtail/django-modelcluster","docs":null,"changelog":"https://github.com/wagtail/django-modelcluster/blob/main/CHANGELOG.txt","pypi":"https://pypi.org/project/django-modelcluster/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["database"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-07-03","last_verified":"2026-08-28","next_check":"2026-07-10","install_tag":null}}