Django clone
Controlled Django model instance replication.
Create copies of a model instance with explicit control on how the instance should be duplicated (limiting fields or related objects copied) with unique field detection. The project is written primarily in Python, distributed under the MIT License license, first published in 2019. Key topics include: bulk-cloning, clone, clonemixin-attributes, cloning, datamodels.
| Python | Django | Downloads | Code Style |
|---|---|---|---|
| PyPI | Test | Vulnerabilities | Coverage | Code Quality | Pre-Commit |
|---|---|---|---|---|---|
django-clone
Create copies of a model instance with explicit control on how the instance should be duplicated (limiting fields or related objects copied) with unique field detection.
This solves the problem introduced by using instance.pk = None and instance.save() which results in copying more object state than required.
Features
- 100% test coverage.
- More control over how a model instance should be duplicated
- Multi Database support i.e Create duplicates on one or more databases.
- Restrict fields used for creating a duplicate instance.
- Detects unique fields and naively adds a suffix
copy {count}to each duplicate instance (for supported fields only). - Optionally differentiate between a duplicate instance and the original by appending a copy suffix to non unique fields (for supported fields only).
Table of Contents
- Installation
- Usage
- Advanced Usage
- Compatibility
- Running locally
- Found a Bug?
- Contributors ✨
Installation
pip
bashpip install django-clone
poetry
bashpoetry add django-clone
Usage
Subclassing the CloneModel

Using the CloneMixin

Using the CloneModel

Duplicating a model instance

Bulk cloning a model

Creating clones without subclassing CloneMixin.
NOTE: :warning:
- This method won't copy over related objects like Many to Many/One to Many relationships.
- Ensure that required fields skipped from being cloned are passed in using the
attrskwargs.

CloneMixin attributes
| Attribute | Description |
|---|---|
DUPLICATE_SUFFIX | Suffix to append to duplicates <br> (NOTE: This requires USE_DUPLICATE_SUFFIX_FOR_NON_UNIQUE_FIELDS <br> to be enabled and supports string fields). |
USE_DUPLICATE_SUFFIX_FOR_NON_UNIQUE_FIELDS | Enable appending the DUPLICATE_SUFFIX to new cloned instances. |
UNIQUE_DUPLICATE_SUFFIX | Suffix to append to unique fields |
USE_UNIQUE_DUPLICATE_SUFFIX | Enable appending the UNIQUE_DUPLICATE_SUFFIX to new cloned instances. |
MAX_UNIQUE_DUPLICATE_QUERY_ATTEMPTS | The max query attempt while generating unique values for a case of unique conflicts. |
Explicit (include only these fields)
| Attribute | Description |
|---|---|
_clone_fields | Restrict the list of fields to copy from the instance (By default: Copies all fields excluding auto-created/non editable model fields) |
_clone_m2m_fields | Restricted Many to many fields (i.e Test.tags) |
_clone_m2o_or_o2m_fields | Restricted Many to One/One to Many fields |
_clone_o2o_fields | Restricted One to One fields |
_clone_linked_m2m_fields | Restricted Many to Many fields that should be linked to the new instance |
Implicit (include all except these fields)
| Attribute | Description |
|---|---|
_clone_excluded_fields | Excluded model fields. |
_clone_excluded_m2m_fields | Excluded many to many fields. |
_clone_excluded_m2o_or_o2m_fields | Excluded Many to One/One to Many fields. |
_clone_excluded_o2o_fields | Excluded one to one fields. |
NOTE: :warning:
- Ensure to either set
_clone_excluded_*or_clone_*. Using both would raise errors.
Django Admin
Duplicating Models from the Django Admin view.

List View

Change View

CloneModelAdmin class attributes

NOTE: :warning:
- Ensure that
model_cloneis placed beforedjango.contrib.admin
pythonINSTALLED_APPS = [ 'model_clone', 'django.contrib.admin', '...', ]
Advanced Usage
Signals
pre_clone_save, post_clone_save

Multi-database support

Compatibility
| Python | Supported version |
|---|---|
| Python2.x | <=2.5.3 |
| Python3.5 | <=2.9.6 |
| Python3.6+ | <=5.3.3 |
| Python3.7+ | All versions |
| Django | Supported version |
|---|---|
| 1.11 | <=2.7.2 |
| 2.x | All versions |
| 3.x | All versions |
| 4.x | All versions |
Running locally
shell$ git clone git@github.com:tj-django/django-clone.git $ make default-user $ make run
Spins up a django server running the demo app.
Visit http://127.0.0.1:8000
Found a Bug?
To file a bug or submit a patch, please head over to django-clone on github.
If you feel generous and want to show some extra appreciation:
Support me with a :star:
Contributors ✨
Thanks goes to these wonderful people:
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tbody> <tr> <td align="center" valign="top" width="14.28%"><a href="http://gerritneven.nl"><img src="https://avatars1.githubusercontent.com/u/2500973?v=4?s=100" width="100px;" alt="Gerben Neven"/><br /><sub><b>Gerben Neven</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/issues?q=author%3Agerbyzation" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=gerbyzation" title="Tests">⚠️</a> <a href="https://github.com/tj-django/django-clone/commits?author=gerbyzation" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="http://sebastian-kindt.com"><img src="https://avatars1.githubusercontent.com/u/2536081?v=4?s=100" width="100px;" alt="Sebastian Kapunkt"/><br /><sub><b>Sebastian Kapunkt</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=SebastianKapunkt" title="Code">💻</a> <a href="https://github.com/tj-django/django-clone/issues?q=author%3ASebastianKapunkt" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=SebastianKapunkt" title="Tests">⚠️</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/andresp99999"><img src="https://avatars0.githubusercontent.com/u/1036725?v=4?s=100" width="100px;" alt="Andrés Portillo"/><br /><sub><b>Andrés Portillo</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/issues?q=author%3Aandresp99999" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://renovate.whitesourcesoftware.com"><img src="https://avatars0.githubusercontent.com/u/25180681?v=4?s=100" width="100px;" alt="WhiteSource Renovate"/><br /><sub><b>WhiteSource Renovate</b></sub></a><br /><a href="#maintenance-renovate-bot" title="Maintenance">🚧</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/yuekui"><img src="https://avatars2.githubusercontent.com/u/2561450?v=4?s=100" width="100px;" alt="Yuekui"/><br /><sub><b>Yuekui</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=yuekui" title="Code">💻</a> <a href="https://github.com/tj-django/django-clone/issues?q=author%3Ayuekui" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=yuekui" title="Tests">⚠️</a> <a href="https://github.com/tj-django/django-clone/commits?author=yuekui" title="Documentation">📖</a> <a href="#maintenance-yuekui" title="Maintenance">🚧</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/diesieben07"><img src="https://avatars.githubusercontent.com/u/1915984?v=4?s=100" width="100px;" alt="Take Weiland"/><br /><sub><b>Take Weiland</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=diesieben07" title="Tests">⚠️</a> <a href="https://github.com/tj-django/django-clone/issues?q=author%3Adiesieben07" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=diesieben07" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ptrck"><img src="https://avatars.githubusercontent.com/u/1259703?v=4?s=100" width="100px;" alt="Patrick"/><br /><sub><b>Patrick</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/issues?q=author%3Aptrck" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=ptrck" title="Code">💻</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://github.com/Akollek"><img src="https://avatars.githubusercontent.com/u/5873158?v=4?s=100" width="100px;" alt="Amiel Kollek"/><br /><sub><b>Amiel Kollek</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=Akollek" title="Code">💻</a> <a href="https://github.com/tj-django/django-clone/issues?q=author%3AAkollek" title="Bug reports">🐛</a> <a href="https://github.com/tj-django/django-clone/commits?author=Akollek" title="Tests">⚠️</a></td> <td align="center" valign="top" width="14.28%"><a href="https://erictheise.com/"><img src="https://avatars.githubusercontent.com/u/317680?v=4?s=100" width="100px;" alt="Eric Theise"/><br /><sub><b>Eric Theise</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=erictheise" title="Documentation">📖</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/DanielSchaffer"><img src="https://avatars.githubusercontent.com/u/334487?v=4?s=100" width="100px;" alt="Daniel Schaffer"/><br /><sub><b>Daniel Schaffer</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=DanielSchaffer" title="Code">💻</a> <a href="https://github.com/tj-django/django-clone/commits?author=DanielSchaffer" title="Tests">⚠️</a></td> <td align="center" valign="top" width="14.28%"><a href="http://damianb.dev"><img src="https://avatars.githubusercontent.com/u/4206989?v=4?s=100" width="100px;" alt="Damian Barabonkov"/><br /><sub><b>Damian Barabonkov</b></sub></a><br /><a href="https://github.com/tj-django/django-clone/commits?author=DamianB-BitFlipper" title="Code">💻</a> <a href="https://github.com/tj-django/django-clone/commits?author=DamianB-BitFlipper" title="Tests">⚠️</a></td> </tr> </tbody> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END -->This project follows the all-contributors specification. Contributions of any kind welcome!
Contributors
Showing top 12 contributors by commit count.
jackton1
880 commits
renovate[bot]
226 commits
renovate-bot
121 commits
github-actions[bot]
114 commits
pre-commit-ci[bot]
85 commits
yuekui
25 commits
allcontributors[bot]
21 commits
dependabot[bot]
19 commits
repo-ranger[bot]
16 commits
SebastianKapunkt
5 commits
dependabot-preview[bot]
3 commits
DanielSchaffer
3 commits

