diff --git a/mssql/features.py b/mssql/features.py index 8c1d7ff..bca20ca 100644 --- a/mssql/features.py +++ b/mssql/features.py @@ -60,6 +60,8 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_default_keyword_in_insert = True supports_expression_defaults = True supports_default_keyword_in_bulk_insert = True + supports_stored_generated_columns = True + supports_virtual_generated_columns = True @cached_property def has_zoneinfo_database(self): diff --git a/mssql/schema.py b/mssql/schema.py index bdf08ae..034ca64 100644 --- a/mssql/schema.py +++ b/mssql/schema.py @@ -384,6 +384,14 @@ def _delete_deferred_unique_indexes_for_field(self, field): def _add_deferred_unique_index_for_field(self, field, statement): self._deferred_unique_indexes[str(field)].append(statement) + def _column_generated_sql(self, field): + """Return the SQL to use in a GENERATED ALWAYS clause.""" + expression_sql, params = field.generated_sql(self.connection) + persistency_sql = "PERSISTED" if field.db_persist else "" + if params: + expression_sql = expression_sql % tuple(self.quote_value(p) for p in params) + return f"AS {expression_sql} {persistency_sql}" + def _alter_field(self, model, old_field, new_field, old_type, new_type, old_db_params, new_db_params, strict=False): """Actually perform a "physical" (non-ManyToMany) field update.""" @@ -1016,6 +1024,9 @@ def add_field(self, model, field): # It might not actually have a column behind it if definition is None: return + # Remove column type from definition if field is generated + if (django_version >= (5,0) and field.generated): + definition = definition[definition.find('AS'):] # Nullable columns with default values require 'WITH VALUES' to set existing rows if 'DEFAULT' in definition and field.null: definition = definition.replace('NULL', 'WITH VALUES') @@ -1218,6 +1229,9 @@ def create_model(self, model): definition, extra_params = self.column_sql(model, field) if definition is None: continue + # Remove column type from definition if field is generated + if (django_version >= (5,0) and field.generated): + definition = definition[definition.find('AS'):] if (self.connection.features.supports_nullable_unique_constraints and not field.many_to_many and field.null and field.unique):