diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 84089d5c0c6..d3c6a55a6b7 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -51,11 +51,14 @@ class View(models.Model): ], limit=1) if not website_specific_view: # Set key to avoid copy() to generate an unique key as we want the specific view to have the same key - website_specific_view = view.copy({'website_id': current_website_id, 'key': view.key}) + copy_vals = {'website_id': current_website_id, 'key': view.key} + if vals.get('inherit_id'): + copy_vals['inherit_id'] = vals['inherit_id'] + website_specific_view = view.copy(copy_vals) view._create_website_specific_pages_for_view(website_specific_view, view.env['website'].browse(current_website_id)) - for inherit_child in view.inherit_children_ids: + for inherit_child in view.inherit_children_ids.filter_duplicate(): # COW won't be triggered if there is already a website_id on the view, we should copy the view ourself if inherit_child.website_id.id == current_website_id: inherit_child.copy({'inherit_id': website_specific_view.id, 'key': inherit_child.key}) diff --git a/addons/website/tests/test_views.py b/addons/website/tests/test_views.py index b16740ad619..5bbfbd07112 100644 --- a/addons/website/tests/test_views.py +++ b/addons/website/tests/test_views.py @@ -520,3 +520,43 @@ class TestCowViewSaving(common.TransactionCase): base_arch_w1 = self.base_view.with_context(website_id=1).read_combined(['arch'])['arch'] self.assertEqual('Hello World' in base_arch, True) self.assertEqual(base_arch, base_arch_w1, "Reading a top level view with or without a website_id in the context should render that exact view..") # ..even if there is a specific view for that one, as read_combined is supposed to render specific inherited view over generic but not specific top level instead of generic top level + + def test_cow_cross_inherit(self): + View = self.env['ir.ui.view'] + total_views = View.search_count([]) + + main_view = View.create({ + 'name': 'Main View', + 'type': 'qweb', + 'arch': 'GENERIC
A
', + 'key': 'website.main_view', + }).with_context(load_all_views=True) + + View.create({ + 'name': 'Child View', + 'mode': 'extension', + 'inherit_id': main_view.id, + 'arch': '
VIEW

B

', + 'key': 'website.child_view', + }) + + child_view_2 = View.with_context(load_all_views=True).create({ + 'name': 'Child View 2', + 'mode': 'extension', + 'inherit_id': main_view.id, + 'arch': 'C', + 'key': 'website.child_view_2', + }) + + # These line doing `write()` are the real tests, it should not be changed and should not crash on xpath. + child_view_2.with_context(website_id=1).write({'arch': 'D'}) + self.assertEqual(total_views + 3 + 1, View.search_count([]), "It should have created the 3 initial generic views and created a child_view_2 specific view") + main_view.with_context(website_id=1).write({'arch': 'SPECIFIC
Z
'}) + self.assertEqual(total_views + 3 + 3, View.search_count([]), "It should have duplicated the Main View tree as a specific tree and then removed the specific view from the generic tree as no more needed") + + generic_view = View.with_context(website_id=None).get_view_id('website.main_view') + specific_view = View.with_context(website_id=1).get_view_id('website.main_view') + generic_view_arch = View.browse(generic_view).with_context(load_all_views=True).read_combined(['arch'])['arch'] + specific_view_arch = View.browse(specific_view).with_context(load_all_views=True, website_id=1).read_combined(['arch'])['arch'] + self.assertEqual(generic_view_arch == 'GENERIC
VIEWC
', True) + self.assertEqual(specific_view_arch == 'SPECIFIC
VIEWD
', True, "Writing on top level view hierarchy with a website in context should write on the view and clone it's inherited views")