Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/base/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,10 @@ def test_invert_boolean_field(self):
initial_repartition[False] += initial_repartition.pop(None, 0)
self.assertEqual(back_repartition, initial_repartition)

def test_convert_m2o_to_m2m(self):
# TODO
return


class TestHelpers(UnitTestCase):
def test_model_table_conversion(self):
Expand Down
56 changes: 56 additions & 0 deletions src/util/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1585,3 +1585,59 @@ def update_server_actions_fields(cr, src_model, dst_model=None, fields_mapping=N
) % {"src_model": src_model, "dst_model": dst_model, "actions": ", ".join(action_names)}

add_to_migration_reports(message=msg, category="Server Actions")


def convert_m2o_to_m2m(cr, origin_model, m2o_field, m2m_field):
"""
TODO
"""
_validate_model(origin_model)

if not table_exists(cr, m2m_field):
raise SleepyDeveloperError("m2m table should already exist warning")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this util should create the m2m the table (auto key?).

Still I don't get what you are checking here. Why should there be a table with the name of the m2m_field? Maybe you wanted to check a column?

If we auto-create the m2m table, we will allow simpler code for fields that are introduced as m2o and later changed to m2m in the same major version --think 18.2 and 18.4 for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. I did not want to duplicate the logic in create_m2m and/or provide the same kind of arguments here. But it is necessary. I guess I can close this in favor of #306

Copy link
Contributor

@aj-fuentes aj-fuentes Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just move your commit there... not sure if that's what you intend to do :)

EDIT (by Pirols): Communication hiccup solved in pm: this PR is not #304 and #306 is not #305.


origin_table = table_of_model(cr, origin_model)

cr.execute(
"""
SELECT kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON kcu.constraint_name = tc.constraint_name
AND kcu.table_schema = tc.table_schema
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND tc.table_name = %s
""",
[origin_table],
)
for column_name, foreign_table_name, foreign_column_name in cr.fetchall():
if foreign_table_name == origin_table:
origin_table_column = column_name
origin_table_fk_column = foreign_column_name
else:
other_table_column = column_name

cr.execute(
format_query(
cr,
"""
INSERT INTO {m2m_field} ({origin_table_column}, {other_table_column})
SELECT {origin_table_fk_column}, {m2o_field}
FROM {origin_table}
WHERE {m2o_field} IS NOT NULL
""",
m2m_field=m2m_field,
m2o_field=m2o_field,
origin_table_fk_column=origin_table_fk_column,
origin_table_column=origin_table_column,
other_table_column=other_table_column,
origin_table=origin_table,
)
)

remove_column(cr, origin_table, m2o_field)
rename_field(cr, origin_model, m2o_field, m2m_field)