Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve default copy method to also copy placeholders and plugins #345

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
38 changes: 34 additions & 4 deletions djangocms_versioning/datastructures.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -202,8 +203,11 @@
"""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
Expand All @@ -219,5 +223,31 @@
# 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 = []

Check warning on line 234 in djangocms_versioning/datastructures.py

View check run for this annotation

Codecov / codecov/patch

djangocms_versioning/datastructures.py#L234

Added line #L234 was not covered by tests
for placeholder in getattr(original_content, field.name).all():
placeholder_fields = {

Check warning on line 236 in djangocms_versioning/datastructures.py

View check run for this annotation

Codecov / codecov/patch

djangocms_versioning/datastructures.py#L236

Added line #L236 was not covered by tests
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)

Check warning on line 245 in djangocms_versioning/datastructures.py

View check run for this annotation

Codecov / codecov/patch

djangocms_versioning/datastructures.py#L244-L245

Added lines #L244 - L245 were not covered by tests
# Copy plugins
placeholder.copy_plugins(new_placeholder)
new_placeholders.append(new_placeholder)
getattr(new_content, field.name).add(*new_placeholders)

Check warning on line 249 in djangocms_versioning/datastructures.py

View check run for this annotation

Codecov / codecov/patch

djangocms_versioning/datastructures.py#L247-L249

Added lines #L247 - L249 were not covered by tests
if hasattr(new_content, "copy_relations"):
if callable(new_content.copy_relations):
new_content.copy_relations()

Check warning on line 252 in djangocms_versioning/datastructures.py

View check run for this annotation

Codecov / codecov/patch

djangocms_versioning/datastructures.py#L252

Added line #L252 was not covered by tests
return new_content