Loading django/db/backends/schema.py +21 −7 Original line number Diff line number Diff line Loading @@ -59,21 +59,27 @@ class BaseDatabaseSchemaEditor(object): # State-managing methods def start(self): "Marks the start of a schema-altering run" """ Marks the start of a schema-altering run. """ self.deferred_sql = [] self.connection.commit_unless_managed() self.connection.enter_transaction_management() self.connection.managed(True) def commit(self): "Finishes a schema-altering run" """ Finishes a schema-altering run. """ for sql in self.deferred_sql: self.execute(sql) self.connection.commit() self.connection.leave_transaction_management() def rollback(self): "Tries to roll back a schema-altering run. Call instead of commit()" """ Tries to roll back a schema-altering run. Call instead of commit(). """ if not self.connection.features.can_rollback_ddl: raise RuntimeError("Cannot rollback schema changes on this backend") self.connection.rollback() Loading Loading @@ -137,7 +143,9 @@ class BaseDatabaseSchemaEditor(object): return sql, params def effective_default(self, field): "Returns a field's effective database default value" """ Returns a field's effective database default value """ if field.has_default(): default = field.get_default() elif not field.null and field.blank and field.empty_strings_allowed: Loading Loading @@ -580,7 +588,9 @@ class BaseDatabaseSchemaEditor(object): ) def _alter_many_to_many(self, model, old_field, new_field, strict): "Alters M2Ms to repoint their to= endpoints." """ Alters M2Ms to repoint their to= endpoints. """ # Rename the through table self.alter_db_table(old_field.rel.through, old_field.rel.through._meta.db_table, new_field.rel.through._meta.db_table) # Repoint the FK to the other side Loading @@ -591,7 +601,9 @@ class BaseDatabaseSchemaEditor(object): ) def _create_index_name(self, model, column_names, suffix=""): "Generates a unique name for an index/unique constraint." """ Generates a unique name for an index/unique constraint. """ # If there is just one column in the index, use a default algorithm from Django if len(column_names) == 1 and not suffix: return truncate_name( Loading @@ -609,7 +621,9 @@ class BaseDatabaseSchemaEditor(object): return index_name def _constraint_names(self, model, column_names=None, unique=None, primary_key=None, index=None, foreign_key=None, check=None): "Returns all constraint names matching the columns and conditions" """ Returns all constraint names matching the columns and conditions """ column_names = set(column_names) if column_names else None constraints = self.connection.introspection.get_constraints(self.connection.cursor(), model._meta.db_table) result = [] Loading django/db/backends/sqlite3/introspection.py +4 −1 Original line number Diff line number Diff line Loading @@ -207,10 +207,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): # Get the PK pk_column = self.get_primary_key_column(cursor, table_name) if pk_column: # SQLite doesn't actually give a name to the PK constraint, # so we invent one. This is fine, as the SQLite backend never # deletes PK constraints by name. constraints["__primary__"] = { "columns": set([pk_column]), "primary_key": True, "unique": False, # It's not actually a unique constraint "unique": False, # It's not actually a unique constraint. "foreign_key": False, "check": False, "index": False, Loading django/db/backends/sqlite3/schema.py +18 −3 Original line number Diff line number Diff line Loading @@ -8,7 +8,9 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): sql_delete_table = "DROP TABLE %(table)s" def _remake_table(self, model, create_fields=[], delete_fields=[], alter_fields=[], rename_fields=[], override_uniques=None): "Shortcut to transform a model from old_model into new_model" """ Shortcut to transform a model from old_model into new_model """ # Work out the new fields dict / mapping body = dict((f.name, f) for f in model._meta.local_fields) mapping = dict((f.column, f.column) for f in model._meta.local_fields) Loading Loading @@ -98,7 +100,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): self._remake_table(model, delete_fields=[field]) def alter_field(self, model, old_field, new_field, strict=False): # Ensure this field is even column-based """ Allows a field's type, uniqueness, nullability, default, column, constraints etc. to be modified. Requires a copy of the old field as well so we can only perform changes that are required. If strict is true, raises errors if the old column does not match old_field precisely. """ old_db_params = old_field.db_parameters(connection=self.connection) old_type = old_db_params['type'] new_db_params = new_field.db_parameters(connection=self.connection) Loading @@ -114,10 +122,17 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): self._remake_table(model, alter_fields=[(old_field, new_field)]) def alter_unique_together(self, model, old_unique_together, new_unique_together): """ Deals with a model changing its unique_together. Note: The input unique_togethers must be doubly-nested, not the single- nested ["foo", "bar"] format. """ self._remake_table(model, override_uniques=new_unique_together) def _alter_many_to_many(self, model, old_field, new_field, strict): "Alters M2Ms to repoint their to= endpoints." """ Alters M2Ms to repoint their to= endpoints. """ # Make a new through table self.create_model(new_field.rel.through) # Copy the data across Loading Loading
django/db/backends/schema.py +21 −7 Original line number Diff line number Diff line Loading @@ -59,21 +59,27 @@ class BaseDatabaseSchemaEditor(object): # State-managing methods def start(self): "Marks the start of a schema-altering run" """ Marks the start of a schema-altering run. """ self.deferred_sql = [] self.connection.commit_unless_managed() self.connection.enter_transaction_management() self.connection.managed(True) def commit(self): "Finishes a schema-altering run" """ Finishes a schema-altering run. """ for sql in self.deferred_sql: self.execute(sql) self.connection.commit() self.connection.leave_transaction_management() def rollback(self): "Tries to roll back a schema-altering run. Call instead of commit()" """ Tries to roll back a schema-altering run. Call instead of commit(). """ if not self.connection.features.can_rollback_ddl: raise RuntimeError("Cannot rollback schema changes on this backend") self.connection.rollback() Loading Loading @@ -137,7 +143,9 @@ class BaseDatabaseSchemaEditor(object): return sql, params def effective_default(self, field): "Returns a field's effective database default value" """ Returns a field's effective database default value """ if field.has_default(): default = field.get_default() elif not field.null and field.blank and field.empty_strings_allowed: Loading Loading @@ -580,7 +588,9 @@ class BaseDatabaseSchemaEditor(object): ) def _alter_many_to_many(self, model, old_field, new_field, strict): "Alters M2Ms to repoint their to= endpoints." """ Alters M2Ms to repoint their to= endpoints. """ # Rename the through table self.alter_db_table(old_field.rel.through, old_field.rel.through._meta.db_table, new_field.rel.through._meta.db_table) # Repoint the FK to the other side Loading @@ -591,7 +601,9 @@ class BaseDatabaseSchemaEditor(object): ) def _create_index_name(self, model, column_names, suffix=""): "Generates a unique name for an index/unique constraint." """ Generates a unique name for an index/unique constraint. """ # If there is just one column in the index, use a default algorithm from Django if len(column_names) == 1 and not suffix: return truncate_name( Loading @@ -609,7 +621,9 @@ class BaseDatabaseSchemaEditor(object): return index_name def _constraint_names(self, model, column_names=None, unique=None, primary_key=None, index=None, foreign_key=None, check=None): "Returns all constraint names matching the columns and conditions" """ Returns all constraint names matching the columns and conditions """ column_names = set(column_names) if column_names else None constraints = self.connection.introspection.get_constraints(self.connection.cursor(), model._meta.db_table) result = [] Loading
django/db/backends/sqlite3/introspection.py +4 −1 Original line number Diff line number Diff line Loading @@ -207,10 +207,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): # Get the PK pk_column = self.get_primary_key_column(cursor, table_name) if pk_column: # SQLite doesn't actually give a name to the PK constraint, # so we invent one. This is fine, as the SQLite backend never # deletes PK constraints by name. constraints["__primary__"] = { "columns": set([pk_column]), "primary_key": True, "unique": False, # It's not actually a unique constraint "unique": False, # It's not actually a unique constraint. "foreign_key": False, "check": False, "index": False, Loading
django/db/backends/sqlite3/schema.py +18 −3 Original line number Diff line number Diff line Loading @@ -8,7 +8,9 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): sql_delete_table = "DROP TABLE %(table)s" def _remake_table(self, model, create_fields=[], delete_fields=[], alter_fields=[], rename_fields=[], override_uniques=None): "Shortcut to transform a model from old_model into new_model" """ Shortcut to transform a model from old_model into new_model """ # Work out the new fields dict / mapping body = dict((f.name, f) for f in model._meta.local_fields) mapping = dict((f.column, f.column) for f in model._meta.local_fields) Loading Loading @@ -98,7 +100,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): self._remake_table(model, delete_fields=[field]) def alter_field(self, model, old_field, new_field, strict=False): # Ensure this field is even column-based """ Allows a field's type, uniqueness, nullability, default, column, constraints etc. to be modified. Requires a copy of the old field as well so we can only perform changes that are required. If strict is true, raises errors if the old column does not match old_field precisely. """ old_db_params = old_field.db_parameters(connection=self.connection) old_type = old_db_params['type'] new_db_params = new_field.db_parameters(connection=self.connection) Loading @@ -114,10 +122,17 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): self._remake_table(model, alter_fields=[(old_field, new_field)]) def alter_unique_together(self, model, old_unique_together, new_unique_together): """ Deals with a model changing its unique_together. Note: The input unique_togethers must be doubly-nested, not the single- nested ["foo", "bar"] format. """ self._remake_table(model, override_uniques=new_unique_together) def _alter_many_to_many(self, model, old_field, new_field, strict): "Alters M2Ms to repoint their to= endpoints." """ Alters M2Ms to repoint their to= endpoints. """ # Make a new through table self.create_model(new_field.rel.through) # Copy the data across Loading