Allow creation of foreign key on non primary key
This commit is contained in:
1 parent
2f84af4adf
commit
e0f11efc94
6 files changed
+44
-19
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Allow creation of foreign key on non primary key
|
||||
* Include context information in access error
|
||||
* Remove trytond-worker max tasks per child option for Python <= 3.10
|
||||
* Do not copy readonly relational fields
|
||||
|
||||
@@ -279,15 +279,16 @@ TableHandler
|
||||
The ``default`` is a method that return the value to fill the new column.
|
||||
``comment`` set as comment for the column.
|
||||
|
||||
.. method:: TableHandler.add_fk(column_name, reference[, on_delete])
|
||||
.. method:: TableHandler.add_fk(columns, reference[, ref_columns[, on_delete])
|
||||
|
||||
Add a foreign key constraint on the named column to target the ``reference``
|
||||
table name.
|
||||
Add a foreign key constraint on the named columns to target the
|
||||
``ref_columns`` of ``reference`` table name.
|
||||
``on_delete`` defines the method to use when foreign record is deleted.
|
||||
|
||||
.. method:: TableHandler.drop_fk(column_name[, table])
|
||||
.. method:: TableHandler.drop_fk(columns[, ref_columns[, table])
|
||||
|
||||
Drop the foreign key constrant on the named column.
|
||||
Drop the foreign key constraint on the named columns targeting the
|
||||
``ref_columns``.
|
||||
``table`` can be used to alter another table.
|
||||
|
||||
.. method:: TableHandler.not_null_action(column_name[, action])
|
||||
|
||||
@@ -396,40 +396,63 @@ class TableHandler(TableHandlerInterface):
|
||||
|
||||
self._update_definitions(columns=True)
|
||||
|
||||
def add_fk(self, column_name, reference, on_delete=None):
|
||||
def add_fk(self, columns, reference, ref_columns=None, on_delete=None):
|
||||
if on_delete is not None:
|
||||
on_delete = on_delete.upper()
|
||||
else:
|
||||
on_delete = 'SET NULL'
|
||||
if isinstance(columns, str):
|
||||
columns = [columns]
|
||||
|
||||
cursor = Transaction().connection.cursor()
|
||||
name = self.convert_name(self.table_name + '_' + column_name + '_fkey')
|
||||
if ref_columns:
|
||||
ref_columns_name = '_' + '_'.join(ref_columns)
|
||||
else:
|
||||
ref_columns_name = ''
|
||||
name = self.convert_name(
|
||||
self.table_name + '_' + '_'.join(columns)
|
||||
+ ref_columns_name + '_fkey')
|
||||
if name in self._constraints:
|
||||
if self._fk_deltypes.get(column_name) != on_delete:
|
||||
self.drop_fk(column_name)
|
||||
add = True
|
||||
for column_name in columns:
|
||||
if self._fk_deltypes.get(column_name) != on_delete:
|
||||
self.drop_fk(columns, ref_columns)
|
||||
add = True
|
||||
break
|
||||
else:
|
||||
add = False
|
||||
else:
|
||||
add = True
|
||||
if add:
|
||||
columns = SQL(', ').join(map(Identifier, columns))
|
||||
if not ref_columns:
|
||||
ref_columns = ['id']
|
||||
ref_columns = SQL(', ').join(map(Identifier, ref_columns))
|
||||
cursor.execute(
|
||||
SQL(
|
||||
"ALTER TABLE {table} "
|
||||
"ADD CONSTRAINT {constraint} "
|
||||
"FOREIGN KEY ({column}) REFERENCES {reference} "
|
||||
"FOREIGN KEY ({columns}) "
|
||||
"REFERENCES {reference} ({ref_columns}) "
|
||||
"ON DELETE {action}"
|
||||
)
|
||||
.format(
|
||||
table=Identifier(self.table_name),
|
||||
constraint=Identifier(name),
|
||||
column=Identifier(column_name),
|
||||
columns=columns,
|
||||
reference=Identifier(reference),
|
||||
ref_columns=ref_columns,
|
||||
action=SQL(on_delete)))
|
||||
self._update_definitions(constraints=True)
|
||||
|
||||
def drop_fk(self, column_name, table=None):
|
||||
self.drop_constraint(column_name + '_fkey', table=table)
|
||||
def drop_fk(self, columns, ref_columns=None, table=None):
|
||||
if isinstance(columns, str):
|
||||
columns = [columns]
|
||||
if ref_columns:
|
||||
ref_columns_name = '_' + '_'.join(ref_columns)
|
||||
else:
|
||||
ref_columns_name = ''
|
||||
self.drop_constraint(
|
||||
'_'.join(columns) + ref_columns_name + '_fkey', table=table)
|
||||
|
||||
def not_null_action(self, column_name, action='add'):
|
||||
if not self.column_exist(column_name):
|
||||
|
||||
@@ -255,10 +255,10 @@ class TableHandler(TableHandlerInterface):
|
||||
|
||||
self._update_definitions(columns=True)
|
||||
|
||||
def add_fk(self, column_name, reference, on_delete=None):
|
||||
def add_fk(self, columns, reference, ref_columns=None, on_delete=None):
|
||||
warnings.warn('Unable to add foreign key with SQLite backend')
|
||||
|
||||
def drop_fk(self, column_name, table=None):
|
||||
def drop_fk(self, columns=None, ref_columns=None, table=None):
|
||||
warnings.warn('Unable to drop foreign key with SQLite backend')
|
||||
|
||||
def not_null_action(self, column_name, action='add'):
|
||||
|
||||
@@ -70,10 +70,10 @@ class TableHandlerInterface(object):
|
||||
def add_column(self, column_name, abstract_type, default=None, comment=''):
|
||||
raise NotImplementedError
|
||||
|
||||
def add_fk(self, column_name, reference, on_delete=None):
|
||||
def add_fk(self, columns, reference, ref_columns=None, on_delete=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def drop_fk(self, column_name, table=None):
|
||||
def drop_fk(self, columns, ref_columns=None, table=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def not_null_action(self, column_name, action='add'):
|
||||
|
||||
@@ -454,7 +454,7 @@ class ModelSQL(ModelStorage):
|
||||
# migration from 3.6
|
||||
table.drop_fk(field_name)
|
||||
elif ref:
|
||||
table.add_fk(field_name, ref, field.ondelete)
|
||||
table.add_fk(field_name, ref, on_delete=field.ondelete)
|
||||
|
||||
required = field.required
|
||||
# Do not set 'NOT NULL' for Binary field as the database column
|
||||
|
||||
Reference in new issue
Block a user