{"id":13502372,"url":"https://github.com/wagtail/django-modelcluster","last_synced_at":"2025-12-18T01:37:47.211Z","repository":{"id":13687345,"uuid":"16381139","full_name":"wagtail/django-modelcluster","owner":"wagtail","description":"Django extension to allow working with 'clusters' of models as a single unit, independently of the database","archived":false,"fork":false,"pushed_at":"2025-01-20T14:21:32.000Z","size":403,"stargazers_count":499,"open_issues_count":26,"forks_count":66,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-03-17T11:06:51.261Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wagtail.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.txt","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-01-30T15:26:05.000Z","updated_at":"2025-03-08T16:40:24.000Z","dependencies_parsed_at":"2023-02-14T09:45:34.369Z","dependency_job_id":"f1898e67-023d-4cca-be6a-ee31c2be9cf3","html_url":"https://github.com/wagtail/django-modelcluster","commit_stats":{"total_commits":359,"total_committers":34,"mean_commits":"10.558823529411764","dds":0.362116991643454,"last_synced_commit":"b2dc5a220bec6e06f917de39d3aa2346c7565b66"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagtail%2Fdjango-modelcluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagtail%2Fdjango-modelcluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagtail%2Fdjango-modelcluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wagtail%2Fdjango-modelcluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wagtail","download_url":"https://codeload.github.com/wagtail/django-modelcluster/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246174207,"owners_count":20735406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T22:02:11.876Z","updated_at":"2025-12-18T01:37:42.173Z","avatar_url":"https://github.com/wagtail.png","language":"Python","readme":"django-modelcluster\n===================\n\nIf you had a data model like this:\n\n.. code-block:: python\n\n class Band(models.Model):\n     name = models.CharField(max_length=255)\n\n class BandMember(models.Model):\n     band = models.ForeignKey('Band', related_name='members', on_delete=models.CASCADE)\n     name = models.CharField(max_length=255)\n\n\nwouldn't it be nice if you could construct bundles of objects like this, independently of the database:\n\n.. code-block:: python\n\n beatles = Band(name='The Beatles')\n beatles.members = [\n     BandMember(name='John Lennon'),\n     BandMember(name='Paul McCartney'),\n ]\n\nUnfortunately, you can't. Objects need to exist in the database for foreign key relations to work:\n\n.. code-block:: python\n\n IntegrityError: null value in column \"band_id\" violates not-null constraint\n\nBut what if you could? There are all sorts of scenarios where you might want to work with a 'cluster' of related objects, without necessarily holding them in the database: maybe you want to render a preview of the data the user has just submitted, prior to saving. Maybe you need to construct a tree of things, serialize them and hand them off to some external system. Maybe you have a workflow where your models exist in an incomplete 'draft' state for an extended time, or you need to handle multiple revisions, and you don't want to redesign your database around that requirement.\n\n**django-modelcluster** extends Django's foreign key relations to make this possible. It introduces a new type of relation, *ParentalKey*, where the related models are stored locally to the 'parent' model until the parent is explicitly saved. Up to that point, the related models can still be accessed through a subset of the QuerySet API:\n\n.. code-block:: python\n \n from modelcluster.models import ClusterableModel\n from modelcluster.fields import ParentalKey\n \n \n class Band(ClusterableModel):\n     name = models.CharField(max_length=255)\n\n class BandMember(models.Model):\n     band = ParentalKey('Band', related_name='members', on_delete=models.CASCADE)\n     name = models.CharField(max_length=255)\n\n\n \u003e\u003e\u003e beatles = Band(name='The Beatles')\n \u003e\u003e\u003e beatles.members = [\n ...     BandMember(name='John Lennon'),\n ...     BandMember(name='Paul McCartney'),\n ... ]\n \u003e\u003e\u003e [member.name for member in beatles.members.all()]\n ['John Lennon', 'Paul McCartney']\n \u003e\u003e\u003e beatles.members.add(BandMember(name='George Harrison'))\n \u003e\u003e\u003e beatles.members.count()\n 3\n \u003e\u003e\u003e beatles.save()  # only now are the records written to the database\n\nFor more examples, see the unit tests.\n\n\nMany-to-many relations\n----------------------\n\nFor many-to-many relations, a corresponding *ParentalManyToManyField* is available:\n\n.. code-block:: python\n\n from modelcluster.models import ClusterableModel\n from modelcluster.fields import ParentalManyToManyField\n\n class Movie(ClusterableModel):\n     title = models.CharField(max_length=255)\n     actors = ParentalManyToManyField('Actor', related_name='movies')\n\n class Actor(models.Model):\n     name = models.CharField(max_length=255)\n\n\n \u003e\u003e\u003e harrison_ford = Actor.objects.create(name='Harrison Ford')\n \u003e\u003e\u003e carrie_fisher = Actor.objects.create(name='Carrie Fisher')\n \u003e\u003e\u003e star_wars = Movie(title='Star Wars')\n \u003e\u003e\u003e star_wars.actors = [harrison_ford, carrie_fisher]\n \u003e\u003e\u003e blade_runner = Movie(title='Blade Runner')\n \u003e\u003e\u003e blade_runner.actors.add(harrison_ford)\n \u003e\u003e\u003e star_wars.actors.count()\n 2\n \u003e\u003e\u003e [movie.title for movie in harrison_ford.movies.all()]  # the Movie records are not in the database yet\n []\n \u003e\u003e\u003e star_wars.save()  # Star Wars now exists in the database (along with the 'actor' relations)\n \u003e\u003e\u003e [movie.title for movie in harrison_ford.movies.all()]\n ['Star Wars']\n\nNote that ``ParentalManyToManyField`` is defined on the parent model rather than the related model, just as a standard ``ManyToManyField`` would be. Also note that the related objects - the ``Actor`` instances in the above example - must exist in the database before being associated with the parent record. (The ``ParentalManyToManyField`` allows the relations between Movies and Actors to be stored in memory without writing to the database, but not the ``Actor`` records themselves.)\n\n\nIntrospection\n-------------\nIf you need to find out which child relations exist on a parent model - to create a deep copy of the model and all its children, say - use the ``modelcluster.models.get_all_child_relations`` function:\n\n.. code-block:: python\n\n \u003e\u003e\u003e from modelcluster.models import get_all_child_relations\n \u003e\u003e\u003e get_all_child_relations(Band)\n [\u003cRelatedObject: tests:bandmember related to band\u003e, \u003cRelatedObject: tests:album related to band\u003e]\n\nThis includes relations that are defined on any superclasses of the parent model.\n\nTo retrieve a list of all ParentalManyToManyFields defined on a parent model, use ``modelcluster.models.get_all_child_m2m_relations``:\n\n.. code-block:: python\n\n \u003e\u003e\u003e from modelcluster.models import get_all_child_m2m_relations\n \u003e\u003e\u003e get_all_child_m2m_relations(Movie)\n [\u003cmodelcluster.fields.ParentalManyToManyField: actors\u003e]\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwagtail%2Fdjango-modelcluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwagtail%2Fdjango-modelcluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwagtail%2Fdjango-modelcluster/lists"}