Description
We have experienced breakages in django-cms due to the changes introduced in django-treebeard 4.5, the following change appears to have caused pain: #192
Some details of the issue and usage:
The usage in django-cms is a model that is being copied (not yet saved) and the _state.created is False. I'm not sure if this is misuse from the CMS or an oversight in django-treebeard.
The following code creates a copy of a model and then later tries to add a root node:
if plugin_model != CMSPlugin:
new_plugin = deepcopy(source_plugin)
new_plugin.pk = None
new_plugin.id = None
new_plugin.language = language or new_plugin.language
new_plugin.placeholder = placeholder
new_plugin.parent = parent
new_plugin.numchild = 0
...
if parent:
new_plugin = parent.add_child(instance=new_plugin)
else:
new_plugin = CMSPlugin.add_root(instance=new_plugin)
This does appear to follow guidelines from Django regarding copying a model: https://docs.djangoproject.com/en/3.2/topics/db/queries/#copying-model-instances
I suspect the deepcopy exists to ensure that all of the plugin children are carried along too, a fundamental feature for the cms: https://www.programiz.com/python-programming/shallow-deep-copy
Failing test, one of many:
ERROR: test_create_page_type (cms.tests.test_admin.AdminFormsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/aiky30/Projects/aiky30-github/django-cms/cms/tests/test_admin.py", line 980, in test_create_page_type
page.publish('en')
File "/Users/aiky30/Projects/aiky30-github/django-cms/cms/models/pagemodel.py", line 982, in publish
self._copy_contents(public_page, language)
File "/Users/aiky30/Projects/aiky30-github/django-cms/cms/models/pagemodel.py", line 628, in _copy_contents
placeholder.copy_plugins(target_placeholder, language=language)
File "/Users/aiky30/Projects/aiky30-github/django-cms/cms/models/placeholdermodel.py", line 577, in copy_plugins
root_plugin=root_plugin,
File "/Users/aiky30/Projects/aiky30-github/django-cms/cms/utils/plugins.py", line 213, in copy_plugins_to_placeholder
new_plugin = CMSPlugin.add_root(instance=new_plugin)
File "/Users/aiky30/Projects/aiky30-github/django-cms/venv/lib/python3.7/site-packages/treebeard/mp_tree.py", line 617, in add_root
return MP_AddRootHandler(cls, **kwargs).process()
File "/Users/aiky30/Projects/aiky30-github/django-cms/venv/lib/python3.7/site-packages/treebeard/mp_tree.py", line 326, in process
raise NodeAlreadySaved("Attempted to add a tree node that is "\
treebeard.exceptions.NodeAlreadySaved: Attempted to add a tree node that is already in the database
The code causing the error in the test
https://github.com/django-cms/django-cms/blob/0e557768af9208f54bea5abe5bb7e629bae2ab88/cms/utils/plugins.py#L213
Also some images showing the state of the model when trying to create a root node: