From 7651a5d7bcd022cb973942c0621567c2b1159bd7 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 24 Jul 2023 11:47:18 +0200 Subject: [PATCH 1/3] feat: Let default_copy also copy PlaceholderRelationFields --- djangocms_versioning/datastructures.py | 29 ++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/djangocms_versioning/datastructures.py b/djangocms_versioning/datastructures.py index 39b2deba..bfb982dd 100644 --- a/djangocms_versioning/datastructures.py +++ b/djangocms_versioning/datastructures.py @@ -1,5 +1,6 @@ from itertools import chain +from cms.models import Placeholder, PlaceholderRelationField from django.contrib.contenttypes.models import ContentType from django.db.models import Max, Prefetch from django.utils.functional import cached_property @@ -219,5 +220,29 @@ def default_copy(original_content): # don't copy primary key because we're creating a new obj if content_model._meta.pk.name != field.name } - # Use original manager to avoid creating a new draft version here! - return content_model._original_manager.create(**content_fields) + # Use original manager to not create a new Version object here + new_content = content_model._original_manager.create(**content_fields) + + # Now copy PlaceholderRelationFields + for field in content_model._meta.private_fields: + # Copy PlaceholderRelationFields + if isinstance(field, PlaceholderRelationField): + # Copy placeholders + new_placeholders = [] + for placeholder in getattr(original_content, field.name).all(): + placeholder_fields = { + field.name: getattr(placeholder, field.name) + for field in Placeholder._meta.fields + # don't copy primary key because we're creating a new obj + # and handle the source field later + if field.name not in [Placeholder._meta.pk.name, "source"] + } + if placeholder.source: + placeholder_fields["source"] = new_content + new_placeholder = Placeholder.objects.create(**placeholder_fields) + # Copy plugins + placeholder.copy_plugins(new_placeholder) + new_placeholders.append(new_placeholder) + getattr(new_content, field.name).add(*new_placeholders) + + return new_content From 026d550908fc123f7c71152edbc5ffd9c42a625f Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 24 Jul 2023 11:48:45 +0200 Subject: [PATCH 2/3] Clarify comment --- djangocms_versioning/datastructures.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/djangocms_versioning/datastructures.py b/djangocms_versioning/datastructures.py index bfb982dd..c5f7b51c 100644 --- a/djangocms_versioning/datastructures.py +++ b/djangocms_versioning/datastructures.py @@ -203,8 +203,11 @@ def default_copy(original_content): """Copy all fields of the original content object exactly as they are and return a new content object which is different only in its pk. - NOTE: This will only work for very simple content objects. This will - throw exceptions on one2one and m2m relationships. And it might not + NOTE: This will only work for very simple content objects. + + It copies placeholders and their plugins. + + It will throw exceptions on one2one and m2m relationships. And it might not be the desired behaviour for some foreign keys (in some cases we would expect a version to copy some of its related objects as well). In such cases a custom copy method must be defined and specified in From f1acb8fc08d8e39c94be2b014f8d6d77f4468cdd Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 24 Jul 2023 12:00:26 +0200 Subject: [PATCH 3/3] Call copy_relations if it exists in verisioned model --- djangocms_versioning/datastructures.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/djangocms_versioning/datastructures.py b/djangocms_versioning/datastructures.py index c5f7b51c..161028be 100644 --- a/djangocms_versioning/datastructures.py +++ b/djangocms_versioning/datastructures.py @@ -247,5 +247,7 @@ def default_copy(original_content): placeholder.copy_plugins(new_placeholder) new_placeholders.append(new_placeholder) getattr(new_content, field.name).add(*new_placeholders) - + if hasattr(new_content, "copy_relations"): + if callable(new_content.copy_relations): + new_content.copy_relations() return new_content