From e09e127faa99915a58a3e4587c7690a23ac2edbd Mon Sep 17 00:00:00 2001 From: David Beitey Date: Fri, 13 Nov 2020 15:04:22 +1000 Subject: [PATCH] Accept deferrable kwarg for schema editor SQL This follows Django 3.1.x's lead in adding `deferrable` as a keyword argument to the `_create_unique_sql` function, following their implementation in the schema editor object. Without accepting this keyword arg, migrations will crash like so: ``` ... File "lib/python3.8/site-packages/django/db/backends/base/schema.py", line 360, in add_constraint sql = constraint.create_sql(model, self) File "lib/python3.8/site-packages/django/db/models/constraints.py", line 118, in create_sql return schema_editor._create_unique_sql( TypeError: _create_unique_sql() got an unexpected keyword argument 'deferrable' ``` This also adjusts the implementation to call `self_deferrable_constraint_sql(...)` with the deferrable arg; in this backend's case the return value is an empty string (like it is currently hardcoded). Essentially it's the same result but allows flexibility if this backend ever supported deferrable constraints. Backwards compatibility is maintained by checking for the passing of a deferrable keyword argument to the create sql function (not provided on earlier Django versions before 3.1) and that the database backend supports deferral for unique indexes. --- sql_server/pyodbc/schema.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sql_server/pyodbc/schema.py b/sql_server/pyodbc/schema.py index 38bc80aa..b7188228 100644 --- a/sql_server/pyodbc/schema.py +++ b/sql_server/pyodbc/schema.py @@ -1,5 +1,6 @@ import binascii import datetime +import django from django.db.backends.base.schema import ( BaseDatabaseSchemaEditor, @@ -677,7 +678,10 @@ def add_field(self, model, field): if self.connection.features.connection_persists_old_columns: self.connection.close() - def _create_unique_sql(self, model, columns, name=None, condition=None): + def _create_unique_sql(self, model, columns, name=None, condition=None, deferrable=None): + if (deferrable and not getattr(self.connection.features, 'supports_deferrable_unique_constraints', False)): + return None + def create_unique_name(*args, **kwargs): return self.quote_name(self._create_index_name(*args, **kwargs)) @@ -687,6 +691,10 @@ def create_unique_name(*args, **kwargs): else: name = self.quote_name(name) columns = Columns(table, columns, self.quote_name) + statement_args = { + "deferrable": self._deferrable_constraint_sql(deferrable) + } if django.VERSION >= (3, 1) else {} + if condition: return Statement( self.sql_create_unique_index, @@ -694,7 +702,7 @@ def create_unique_name(*args, **kwargs): name=name, columns=columns, condition=' WHERE ' + condition, - deferrable='' + **statement_args ) if self.connection.features.supports_partial_indexes else None else: return Statement( @@ -702,7 +710,7 @@ def create_unique_name(*args, **kwargs): table=table, name=name, columns=columns, - deferrable='' + **statement_args ) def _create_index_sql(self, model, fields, *, name=None, suffix='', using='',