From fa2a0c2d02d41610d469597575e3bf644ba5fbef Mon Sep 17 00:00:00 2001 From: LB Johnston Date: Wed, 27 Feb 2019 08:04:56 +1000 Subject: [PATCH] add ability for page.copy to copy ParentalManyToMany field relations --- CHANGELOG.txt | 1 + docs/releases/2.5.rst | 1 + wagtail/core/models.py | 11 +++++++- wagtail/core/tests/test_page_model.py | 39 +++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6c90159282..cd3f386b63 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -20,6 +20,7 @@ Changelog * Fix: Parent page link in page chooser search results no longer navigates away (Asanka Lihiniyagoda, Sævar Öfjörð Magnússon) * Fix: `routablepageurl` tag now correctly omits domain part when multiple sites exist at the same root (Gassan Gousseinov) * Fix: Added missing collection column specifier on document listing template (Sergey Fedoseev) + * Fix: Page Copy will now also copy ParentalManyToMany field relations (LB (Ben Johnston)) 2.4 (19.12.2018) diff --git a/docs/releases/2.5.rst b/docs/releases/2.5.rst index 4b68427f67..94988b3b56 100644 --- a/docs/releases/2.5.rst +++ b/docs/releases/2.5.rst @@ -35,6 +35,7 @@ Bug fixes * Parent page link in page chooser search results no longer navigates away (Asanka Lihiniyagoda, Sævar Öfjörð Magnússon) * ``routablepageurl`` tag now correctly omits domain part when multiple sites exist at the same root (Gassan Gousseinov) * Added missing collection column specifier on document listing template (Sergey Fedoseev) + * Page Copy will now also copy ParentalManyToMany field relations (LB (Ben Johnston)) Upgrade considerations diff --git a/wagtail/core/models.py b/wagtail/core/models.py index ea94529270..33b4d10802 100644 --- a/wagtail/core/models.py +++ b/wagtail/core/models.py @@ -22,7 +22,8 @@ from django.utils import timezone from django.utils.functional import cached_property from django.utils.text import capfirst, slugify from django.utils.translation import ugettext_lazy as _ -from modelcluster.models import ClusterableModel, get_all_child_relations +from modelcluster.models import ( + ClusterableModel, get_all_child_m2m_relations, get_all_child_relations) from treebeard.mp_tree import MP_Node from wagtail.core.query import PageQuerySet, TreeQuerySet @@ -1070,6 +1071,14 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase): specific_dict[field.name] = getattr(specific_self, field.name) + # copy child m2m relations + for related_field in get_all_child_m2m_relations(specific_self): + field = getattr(specific_self, related_field.name) + if field and hasattr(field, 'all'): + values = field.all() + if values: + specific_dict[related_field.name] = values + # New instance from prepared dict values, in case the instance class implements multiple levels inheritance page_copy = self.specific_class(**specific_dict) diff --git a/wagtail/core/tests/test_page_model.py b/wagtail/core/tests/test_page_model.py index a268b1467f..5833d396f8 100644 --- a/wagtail/core/tests/test_page_model.py +++ b/wagtail/core/tests/test_page_model.py @@ -16,8 +16,8 @@ from wagtail.core.models import Page, PageManager, Site, get_page_models from wagtail.tests.testapp.models import ( AbstractPage, Advert, AlwaysShowInMenusPage, BlogCategory, BlogCategoryBlogPage, BusinessChild, BusinessIndex, BusinessNowherePage, BusinessSubIndex, CustomManager, CustomManagerPage, - CustomPageQuerySet, EventIndex, EventPage, GenericSnippetPage, ManyToManyBlogPage, MTIBasePage, - MTIChildPage, MyCustomPage, OneToOnePage, PageWithExcludedCopyField, SimplePage, + CustomPageQuerySet, EventCategory, EventIndex, EventPage, GenericSnippetPage, ManyToManyBlogPage, + MTIBasePage, MTIChildPage, MyCustomPage, OneToOnePage, PageWithExcludedCopyField, SimplePage, SingleEventPage, SingletonPage, StandardIndex, TaggedPage) from wagtail.tests.utils import WagtailTestUtils @@ -702,6 +702,41 @@ class TestCopyPage(TestCase): "Child objects defined on the superclass were removed from the original page" ) + def test_copy_page_copies_parental_relations(self): + """Test that a page will be copied with parental many to many relations intact.""" + christmas_event = EventPage.objects.get(url_path='/home/events/christmas/') + summer_category = EventCategory.objects.create(name='Summer') + holiday_category = EventCategory.objects.create(name='Holidays') + + # add parental many to many relations + christmas_event.categories = (summer_category, holiday_category) + christmas_event.save() + + # Copy it + new_christmas_event = christmas_event.copy( + update_attrs={'title': "New christmas event", 'slug': 'new-christmas-event'} + ) + + # check that original eventt is untouched + self.assertEqual( + christmas_event.categories.count(), + 2, + "Child objects (parental many to many) defined on the superclass were removed from the original page" + ) + + # check that parental many to many are copied + self.assertEqual( + new_christmas_event.categories.count(), + 2, + "Child objects (parental many to many) weren't copied" + ) + + # check that the original and copy are related to the same categories + self.assertEqual( + new_christmas_event.categories.all().in_bulk(), + christmas_event.categories.all().in_bulk() + ) + def test_copy_page_copies_revisions(self): christmas_event = EventPage.objects.get(url_path='/home/events/christmas/') christmas_event.save_revision()