From ce815a5f0007fe9be77c20f569e0e28273046342 Mon Sep 17 00:00:00 2001 From: LB Johnston Date: Sun, 17 Mar 2019 17:05:57 +1000 Subject: [PATCH] page.copy to use `exclude_fields_in_copy` child & parental m2m relations - fixes #5099 - test_copy_page_with_excluded_parental_and_child_relations - ensure the tests are wrapped in a try/finally so that the model is always reset back even if tests fail - update page model tests --- CHANGELOG.txt | 1 + docs/releases/2.9.rst | 1 + wagtail/core/models.py | 7 +++ wagtail/core/tests/test_page_model.py | 61 +++++++++++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 3c579e11fc..12bcdb172f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -44,6 +44,7 @@ Changelog * Fix: Mark up a few strings for translation (Luiz Boaretto) * Fix: Invalid focal_point attribute on image edit view (Michał (Quadric) Sieradzki) * Fix: No longer expose the `.delete()` method on the default Page.objects manager (Nick Smith) + * Fix: `exclude_fields_in_copy` on Page models will now work for for modelcluster parental / many to many relations (LB (Ben Johnston)) 2.8.1 (14.04.2020) diff --git a/docs/releases/2.9.rst b/docs/releases/2.9.rst index 32d8404eb4..2591f6840f 100644 --- a/docs/releases/2.9.rst +++ b/docs/releases/2.9.rst @@ -62,6 +62,7 @@ Bug fixes * Mark up a few strings for translation (Luiz Boaretto) * Invalid focal_point attribute on image edit view (Michał (Quadric) Sieradzki) * No longer expose the ``.delete()`` method on the default Page.objects manager (Nick Smith) + * ``exclude_fields_in_copy`` on Page models will now work for for modelcluster parental / many to many relations (LB (Ben Johnston)) Upgrade considerations diff --git a/wagtail/core/models.py b/wagtail/core/models.py index 5ce76ff596..b87ffe085c 100644 --- a/wagtail/core/models.py +++ b/wagtail/core/models.py @@ -1136,6 +1136,10 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase): # copy child m2m relations for related_field in get_all_child_m2m_relations(specific_self): + # Ignore explicitly excluded fields + if related_field.name in exclude_fields: + continue + field = getattr(specific_self, related_field.name) if field and hasattr(field, 'all'): values = field.all() @@ -1180,6 +1184,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase): parental_key_name = child_relation.field.attname child_objects = getattr(specific_self, accessor_name, None) + # Ignore explicitly excluded fields + if accessor_name in exclude_fields: + continue if child_objects: for child_object in child_objects.all(): diff --git a/wagtail/core/tests/test_page_model.py b/wagtail/core/tests/test_page_model.py index d4cc40102e..7e1bad2881 100644 --- a/wagtail/core/tests/test_page_model.py +++ b/wagtail/core/tests/test_page_model.py @@ -1195,6 +1195,67 @@ class TestCopyPage(TestCase): # special_field is in the list to be excluded self.assertNotEqual(page.special_field, new_page.special_field) + def test_copy_page_with_excluded_parental_and_child_relations(self): + """Test that a page will be copied with parental and child relations removed if excluded.""" + + try: + # modify excluded fields for this test + EventPage.exclude_fields_in_copy = ['advert_placements', 'categories', 'signup_link'] + + # set up data + 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 URL (to test excluding a basic field) + christmas_event.signup_link = "https://christmas-is-awesome.com/rsvp" + + # 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 the signup_link was NOT copied + self.assertEqual(christmas_event.signup_link, "https://christmas-is-awesome.com/rsvp") + self.assertEqual(new_christmas_event.signup_link, '') + + # check that original event 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 NOT copied + self.assertEqual( + new_christmas_event.categories.count(), + 0, + "Child objects (parental many to many) were copied but should be excluded" + ) + + # check that child objects on original event were left untouched + self.assertEqual( + christmas_event.advert_placements.count(), + 1, + "Child objects defined on the original superclass were edited when copied" + ) + + # check that child objects were NOT copied + self.assertEqual( + new_christmas_event.advert_placements.count(), + 0, + "Child objects defined on the superclass were copied and should not be" + ) + + finally: + # reset excluded fields for future tests + EventPage.exclude_fields_in_copy = [] + + class TestSubpageTypeBusinessRules(TestCase, WagtailTestUtils): def test_allowed_subpage_models(self):