Skip to content

Commit 88dc6a6

Browse files
committed
[IMP] util.remove_view : remove redundant t-calls
while removing the view, removing the content having t-call in other views which  are calling to have the content of it. As there are many specific fixes available for this, it's better to handle  it in remove_view. Before fix: t-call with the same xml_id will remain in other views that are using it. So during access of that view, the system is raising an error "view not found." ``` <t name="Payment" t-name="website_sale.payment"> <t t-call="website_sale.cart_summary"/> </t> ``` After fix: t-call will be removed, so no error will be raised. ``` <t name="Payment" t-name="website_sale.payment"> </t> ``` Traceback: ``` Error while render the template ValueError: View 'website_sale.cart_summary' in website 1 not found Template: website_sale.payment Path: /t/t/div/div[1]/div/div[4]/div[1]/t Node: <t t-call="website_sale.address_on_payment"/> ``` Part-of: #116 Signed-off-by: Christophe Simonis (chs) <[email protected]>
1 parent 4230096 commit 88dc6a6

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

src/base/tests/test_util.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,3 +1825,65 @@ def test_convert_field_to_html(self):
18251825

18261826
self.assertEqual(default.json_value, '"<p>Test text</p>"')
18271827
self.assertEqual(partner.x_testx, "<p>test partner field</p>")
1828+
1829+
1830+
class TestRemoveView(UnitTestCase):
1831+
def test_remove_view(self):
1832+
test_view_1 = self.env["ir.ui.view"].create(
1833+
{
1834+
"name": "test_view_1",
1835+
"type": "qweb",
1836+
"key": "base.test_view_1",
1837+
"arch": """
1838+
<t t-name="base.test_view_1">
1839+
<div>Test View 1 Content</div>
1840+
</t>
1841+
""",
1842+
}
1843+
)
1844+
self.env["ir.model.data"].create(
1845+
{"name": "test_view_1", "module": "base", "model": "ir.ui.view", "res_id": test_view_1.id}
1846+
)
1847+
test_view_2 = self.env["ir.ui.view"].create(
1848+
{
1849+
"name": "test_view_2",
1850+
"type": "qweb",
1851+
"key": "base.test_view_2",
1852+
"arch": """
1853+
<t t-name="base.test_view_2">
1854+
<t t-call="base.test_view_1"/>
1855+
<div>Test View 2 Content</div>
1856+
</t>
1857+
""",
1858+
}
1859+
)
1860+
test_view_3 = self.env["ir.ui.view"].create(
1861+
{
1862+
"name": "test_view_3",
1863+
"type": "qweb",
1864+
"key": "base.test_view_3",
1865+
"arch": """
1866+
<t t-name="base.test_view_3">
1867+
<t t-call="base.test_view_1"/>
1868+
<t t-call="base.test_view_2"/>
1869+
</t>
1870+
""",
1871+
}
1872+
)
1873+
self.env["ir.model.data"].create(
1874+
{"name": "test_view_3", "module": "base", "model": "ir.ui.view", "res_id": test_view_3.id}
1875+
)
1876+
1877+
# call by xml_id
1878+
util.remove_view(self.env.cr, xml_id="base.test_view_1")
1879+
util.invalidate(test_view_2)
1880+
util.invalidate(test_view_3)
1881+
self.assertFalse(test_view_1.exists())
1882+
self.assertNotIn('t-call="base.test_view_1"', test_view_2.arch_db)
1883+
self.assertNotIn('t-call="base.test_view_1"', test_view_3.arch_db)
1884+
1885+
# call by view_id
1886+
util.remove_view(self.env.cr, view_id=test_view_2.id)
1887+
util.invalidate(test_view_3)
1888+
self.assertFalse(test_view_2.exists())
1889+
self.assertNotIn('t-call="base.test_view_2"', test_view_3.arch_db)

src/util/records.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
from psycopg2.extras import Json, execute_values
1313

1414
try:
15-
from odoo import release
15+
from odoo import modules, release
1616
from odoo.tools.convert import xml_import
1717
from odoo.tools.misc import file_open
1818
from odoo.tools.translate import xml_translate
1919
except ImportError:
20-
from openerp import release
20+
from openerp import modules, release
2121
from openerp.tools.convert import xml_import
2222
from openerp.tools.misc import file_open
2323

@@ -106,6 +106,16 @@ def remove_view(cr, xml_id=None, view_id=None, silent=False, key=None):
106106
for [v_id] in cr.fetchall():
107107
remove_view(cr, view_id=v_id, silent=silent, key=xml_id)
108108

109+
if not key and column_exists(cr, "ir_ui_view", "key"):
110+
cr.execute("SELECT key FROM ir_ui_view WHERE id = %s and key != %s", [view_id, xml_id])
111+
[key] = cr.fetchone() or [None]
112+
113+
# Occurrences of xml_id and key in the t-call of views are to be found and removed.
114+
if xml_id != "?":
115+
_remove_redundant_tcalls(cr, xml_id)
116+
if key and key != xml_id:
117+
_remove_redundant_tcalls(cr, key)
118+
109119
if not view_id:
110120
return
111121

@@ -1784,3 +1794,47 @@ def remove_act_window_view_mode(cr, model, view_mode):
17841794
""",
17851795
[view_mode, default, model, view_mode, view_mode],
17861796
)
1797+
1798+
1799+
def _remove_redundant_tcalls(cr, match):
1800+
"""
1801+
Remove t-calls of the removed view.
1802+
1803+
This function removes the t-calls to `match`.
1804+
1805+
:param str match: t-calls value to remove, typically it would be a view's xml_id or key
1806+
"""
1807+
arch_col = (
1808+
get_value_or_en_translation(cr, "ir_ui_view", "arch_db")
1809+
if column_exists(cr, "ir_ui_view", "arch_db")
1810+
else "arch"
1811+
)
1812+
cr.execute(
1813+
format_query(
1814+
cr,
1815+
"""
1816+
SELECT iv.id,
1817+
imd.module,
1818+
imd.name
1819+
FROM ir_ui_view iv
1820+
LEFT JOIN ir_model_data imd
1821+
ON iv.id = imd.res_id
1822+
AND imd.model = 'ir.ui.view'
1823+
WHERE {} ~ %s
1824+
""",
1825+
sql.SQL(arch_col),
1826+
),
1827+
[r"""\yt-call=(["']){}\1""".format(re.escape(match))],
1828+
)
1829+
standard_modules = set(modules.get_modules()) - {"studio_customization"}
1830+
for vid, module, name in cr.fetchall():
1831+
with edit_view(cr, view_id=vid) as arch:
1832+
for node in arch.findall(".//t[@t-call='{}']".format(match)):
1833+
node.getparent().remove(node)
1834+
if not module or module not in standard_modules:
1835+
_logger.info(
1836+
"The view %swith ID: %s has been updated, removed t-calls to deprecated %r",
1837+
("`{}.{}` ".format(module, name) if module else ""),
1838+
vid,
1839+
match,
1840+
)

0 commit comments

Comments
 (0)