Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

schema.py 49KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. import hashlib
  2. import logging
  3. from datetime import datetime
  4. from django.db.backends.ddl_references import (
  5. Columns, ForeignKeyName, IndexName, Statement, Table,
  6. )
  7. from django.db.backends.utils import split_identifier
  8. from django.db.models import Index
  9. from django.db.transaction import TransactionManagementError, atomic
  10. from django.utils import timezone
  11. from django.utils.encoding import force_bytes
  12. logger = logging.getLogger('django.db.backends.schema')
  13. def _is_relevant_relation(relation, altered_field):
  14. """
  15. When altering the given field, must constraints on its model from the given
  16. relation be temporarily dropped?
  17. """
  18. field = relation.field
  19. if field.many_to_many:
  20. # M2M reverse field
  21. return False
  22. if altered_field.primary_key and field.to_fields == [None]:
  23. # Foreign key constraint on the primary key, which is being altered.
  24. return True
  25. # Is the constraint targeting the field being altered?
  26. return altered_field.name in field.to_fields
  27. def _related_non_m2m_objects(old_field, new_field):
  28. # Filter out m2m objects from reverse relations.
  29. # Return (old_relation, new_relation) tuples.
  30. return zip(
  31. (obj for obj in old_field.model._meta.related_objects if _is_relevant_relation(obj, old_field)),
  32. (obj for obj in new_field.model._meta.related_objects if _is_relevant_relation(obj, new_field))
  33. )
  34. class BaseDatabaseSchemaEditor:
  35. """
  36. This class and its subclasses are responsible for emitting schema-changing
  37. statements to the databases - model creation/removal/alteration, field
  38. renaming, index fiddling, and so on.
  39. """
  40. # Overrideable SQL templates
  41. sql_create_table = "CREATE TABLE %(table)s (%(definition)s)"
  42. sql_rename_table = "ALTER TABLE %(old_table)s RENAME TO %(new_table)s"
  43. sql_retablespace_table = "ALTER TABLE %(table)s SET TABLESPACE %(new_tablespace)s"
  44. sql_delete_table = "DROP TABLE %(table)s CASCADE"
  45. sql_create_column = "ALTER TABLE %(table)s ADD COLUMN %(column)s %(definition)s"
  46. sql_alter_column = "ALTER TABLE %(table)s %(changes)s"
  47. sql_alter_column_type = "ALTER COLUMN %(column)s TYPE %(type)s"
  48. sql_alter_column_null = "ALTER COLUMN %(column)s DROP NOT NULL"
  49. sql_alter_column_not_null = "ALTER COLUMN %(column)s SET NOT NULL"
  50. sql_alter_column_default = "ALTER COLUMN %(column)s SET DEFAULT %(default)s"
  51. sql_alter_column_no_default = "ALTER COLUMN %(column)s DROP DEFAULT"
  52. sql_delete_column = "ALTER TABLE %(table)s DROP COLUMN %(column)s CASCADE"
  53. sql_rename_column = "ALTER TABLE %(table)s RENAME COLUMN %(old_column)s TO %(new_column)s"
  54. sql_update_with_default = "UPDATE %(table)s SET %(column)s = %(default)s WHERE %(column)s IS NULL"
  55. sql_create_check = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s CHECK (%(check)s)"
  56. sql_delete_check = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
  57. sql_create_unique = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s UNIQUE (%(columns)s)"
  58. sql_delete_unique = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
  59. sql_create_fk = (
  60. "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s FOREIGN KEY (%(column)s) "
  61. "REFERENCES %(to_table)s (%(to_column)s)%(deferrable)s"
  62. )
  63. sql_create_inline_fk = None
  64. sql_delete_fk = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
  65. sql_create_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s)%(extra)s"
  66. sql_delete_index = "DROP INDEX %(name)s"
  67. sql_create_pk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s PRIMARY KEY (%(columns)s)"
  68. sql_delete_pk = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
  69. sql_delete_procedure = 'DROP PROCEDURE %(procedure)s'
  70. def __init__(self, connection, collect_sql=False, atomic=True):
  71. self.connection = connection
  72. self.collect_sql = collect_sql
  73. if self.collect_sql:
  74. self.collected_sql = []
  75. self.atomic_migration = self.connection.features.can_rollback_ddl and atomic
  76. # State-managing methods
  77. def __enter__(self):
  78. self.deferred_sql = []
  79. if self.atomic_migration:
  80. self.atomic = atomic(self.connection.alias)
  81. self.atomic.__enter__()
  82. return self
  83. def __exit__(self, exc_type, exc_value, traceback):
  84. if exc_type is None:
  85. for sql in self.deferred_sql:
  86. self.execute(sql)
  87. if self.atomic_migration:
  88. self.atomic.__exit__(exc_type, exc_value, traceback)
  89. # Core utility functions
  90. def execute(self, sql, params=()):
  91. """Execute the given SQL statement, with optional parameters."""
  92. # Don't perform the transactional DDL check if SQL is being collected
  93. # as it's not going to be executed anyway.
  94. if not self.collect_sql and self.connection.in_atomic_block and not self.connection.features.can_rollback_ddl:
  95. raise TransactionManagementError(
  96. "Executing DDL statements while in a transaction on databases "
  97. "that can't perform a rollback is prohibited."
  98. )
  99. # Account for non-string statement objects.
  100. sql = str(sql)
  101. # Log the command we're running, then run it
  102. logger.debug("%s; (params %r)", sql, params, extra={'params': params, 'sql': sql})
  103. if self.collect_sql:
  104. ending = "" if sql.endswith(";") else ";"
  105. if params is not None:
  106. self.collected_sql.append((sql % tuple(map(self.quote_value, params))) + ending)
  107. else:
  108. self.collected_sql.append(sql + ending)
  109. else:
  110. with self.connection.cursor() as cursor:
  111. cursor.execute(sql, params)
  112. def quote_name(self, name):
  113. return self.connection.ops.quote_name(name)
  114. @classmethod
  115. def _digest(cls, *args):
  116. """
  117. Generate a 32-bit digest of a set of arguments that can be used to
  118. shorten identifying names.
  119. """
  120. h = hashlib.md5()
  121. for arg in args:
  122. h.update(force_bytes(arg))
  123. return h.hexdigest()[:8]
  124. # Field <-> database mapping functions
  125. def column_sql(self, model, field, include_default=False):
  126. """
  127. Take a field and return its column definition.
  128. The field must already have had set_attributes_from_name() called.
  129. """
  130. # Get the column's type and use that as the basis of the SQL
  131. db_params = field.db_parameters(connection=self.connection)
  132. sql = db_params['type']
  133. params = []
  134. # Check for fields that aren't actually columns (e.g. M2M)
  135. if sql is None:
  136. return None, None
  137. # Work out nullability
  138. null = field.null
  139. # If we were told to include a default value, do so
  140. include_default = include_default and not self.skip_default(field)
  141. if include_default:
  142. default_value = self.effective_default(field)
  143. if default_value is not None:
  144. if self.connection.features.requires_literal_defaults:
  145. # Some databases can't take defaults as a parameter (oracle)
  146. # If this is the case, the individual schema backend should
  147. # implement prepare_default
  148. sql += " DEFAULT %s" % self.prepare_default(default_value)
  149. else:
  150. sql += " DEFAULT %s"
  151. params += [default_value]
  152. # Oracle treats the empty string ('') as null, so coerce the null
  153. # option whenever '' is a possible value.
  154. if (field.empty_strings_allowed and not field.primary_key and
  155. self.connection.features.interprets_empty_strings_as_nulls):
  156. null = True
  157. if null and not self.connection.features.implied_column_null:
  158. sql += " NULL"
  159. elif not null:
  160. sql += " NOT NULL"
  161. # Primary key/unique outputs
  162. if field.primary_key:
  163. sql += " PRIMARY KEY"
  164. elif field.unique:
  165. sql += " UNIQUE"
  166. # Optionally add the tablespace if it's an implicitly indexed column
  167. tablespace = field.db_tablespace or model._meta.db_tablespace
  168. if tablespace and self.connection.features.supports_tablespaces and field.unique:
  169. sql += " %s" % self.connection.ops.tablespace_sql(tablespace, inline=True)
  170. # Return the sql
  171. return sql, params
  172. def skip_default(self, field):
  173. """
  174. Some backends don't accept default values for certain columns types
  175. (i.e. MySQL longtext and longblob).
  176. """
  177. return False
  178. def prepare_default(self, value):
  179. """
  180. Only used for backends which have requires_literal_defaults feature
  181. """
  182. raise NotImplementedError(
  183. 'subclasses of BaseDatabaseSchemaEditor for backends which have '
  184. 'requires_literal_defaults must provide a prepare_default() method'
  185. )
  186. def effective_default(self, field):
  187. """Return a field's effective database default value."""
  188. if field.has_default():
  189. default = field.get_default()
  190. elif not field.null and field.blank and field.empty_strings_allowed:
  191. if field.get_internal_type() == "BinaryField":
  192. default = bytes()
  193. else:
  194. default = str()
  195. elif getattr(field, 'auto_now', False) or getattr(field, 'auto_now_add', False):
  196. default = datetime.now()
  197. internal_type = field.get_internal_type()
  198. if internal_type == 'DateField':
  199. default = default.date
  200. elif internal_type == 'TimeField':
  201. default = default.time
  202. elif internal_type == 'DateTimeField':
  203. default = timezone.now
  204. else:
  205. default = None
  206. # If it's a callable, call it
  207. if callable(default):
  208. default = default()
  209. # Convert the value so it can be sent to the database.
  210. return field.get_db_prep_save(default, self.connection)
  211. def quote_value(self, value):
  212. """
  213. Return a quoted version of the value so it's safe to use in an SQL
  214. string. This is not safe against injection from user code; it is
  215. intended only for use in making SQL scripts or preparing default values
  216. for particularly tricky backends (defaults are not user-defined, though,
  217. so this is safe).
  218. """
  219. raise NotImplementedError()
  220. # Actions
  221. def create_model(self, model):
  222. """
  223. Create a table and any accompanying indexes or unique constraints for
  224. the given `model`.
  225. """
  226. # Create column SQL, add FK deferreds if needed
  227. column_sqls = []
  228. params = []
  229. for field in model._meta.local_fields:
  230. # SQL
  231. definition, extra_params = self.column_sql(model, field)
  232. if definition is None:
  233. continue
  234. # Check constraints can go on the column SQL here
  235. db_params = field.db_parameters(connection=self.connection)
  236. if db_params['check']:
  237. definition += " CHECK (%s)" % db_params['check']
  238. # Autoincrement SQL (for backends with inline variant)
  239. col_type_suffix = field.db_type_suffix(connection=self.connection)
  240. if col_type_suffix:
  241. definition += " %s" % col_type_suffix
  242. params.extend(extra_params)
  243. # FK
  244. if field.remote_field and field.db_constraint:
  245. to_table = field.remote_field.model._meta.db_table
  246. to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column
  247. if self.sql_create_inline_fk:
  248. definition += " " + self.sql_create_inline_fk % {
  249. "to_table": self.quote_name(to_table),
  250. "to_column": self.quote_name(to_column),
  251. }
  252. elif self.connection.features.supports_foreign_keys:
  253. self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
  254. # Add the SQL to our big list
  255. column_sqls.append("%s %s" % (
  256. self.quote_name(field.column),
  257. definition,
  258. ))
  259. # Autoincrement SQL (for backends with post table definition variant)
  260. if field.get_internal_type() in ("AutoField", "BigAutoField"):
  261. autoinc_sql = self.connection.ops.autoinc_sql(model._meta.db_table, field.column)
  262. if autoinc_sql:
  263. self.deferred_sql.extend(autoinc_sql)
  264. # Add any unique_togethers (always deferred, as some fields might be
  265. # created afterwards, like geometry fields with some backends)
  266. for fields in model._meta.unique_together:
  267. columns = [model._meta.get_field(field).column for field in fields]
  268. self.deferred_sql.append(self._create_unique_sql(model, columns))
  269. # Make the table
  270. sql = self.sql_create_table % {
  271. "table": self.quote_name(model._meta.db_table),
  272. "definition": ", ".join(column_sqls)
  273. }
  274. if model._meta.db_tablespace:
  275. tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
  276. if tablespace_sql:
  277. sql += ' ' + tablespace_sql
  278. # Prevent using [] as params, in the case a literal '%' is used in the definition
  279. self.execute(sql, params or None)
  280. # Add any field index and index_together's (deferred as SQLite3 _remake_table needs it)
  281. self.deferred_sql.extend(self._model_indexes_sql(model))
  282. # Make M2M tables
  283. for field in model._meta.local_many_to_many:
  284. if field.remote_field.through._meta.auto_created:
  285. self.create_model(field.remote_field.through)
  286. def delete_model(self, model):
  287. """Delete a model from the database."""
  288. # Handle auto-created intermediary models
  289. for field in model._meta.local_many_to_many:
  290. if field.remote_field.through._meta.auto_created:
  291. self.delete_model(field.remote_field.through)
  292. # Delete the table
  293. self.execute(self.sql_delete_table % {
  294. "table": self.quote_name(model._meta.db_table),
  295. })
  296. # Remove all deferred statements referencing the deleted table.
  297. for sql in list(self.deferred_sql):
  298. if isinstance(sql, Statement) and sql.references_table(model._meta.db_table):
  299. self.deferred_sql.remove(sql)
  300. def add_index(self, model, index):
  301. """Add an index on a model."""
  302. self.execute(index.create_sql(model, self))
  303. def remove_index(self, model, index):
  304. """Remove an index from a model."""
  305. self.execute(index.remove_sql(model, self))
  306. def alter_unique_together(self, model, old_unique_together, new_unique_together):
  307. """
  308. Deal with a model changing its unique_together. The input
  309. unique_togethers must be doubly-nested, not the single-nested
  310. ["foo", "bar"] format.
  311. """
  312. olds = {tuple(fields) for fields in old_unique_together}
  313. news = {tuple(fields) for fields in new_unique_together}
  314. # Deleted uniques
  315. for fields in olds.difference(news):
  316. self._delete_composed_index(model, fields, {'unique': True}, self.sql_delete_unique)
  317. # Created uniques
  318. for fields in news.difference(olds):
  319. columns = [model._meta.get_field(field).column for field in fields]
  320. self.execute(self._create_unique_sql(model, columns))
  321. def alter_index_together(self, model, old_index_together, new_index_together):
  322. """
  323. Deal with a model changing its index_together. The input
  324. index_togethers must be doubly-nested, not the single-nested
  325. ["foo", "bar"] format.
  326. """
  327. olds = {tuple(fields) for fields in old_index_together}
  328. news = {tuple(fields) for fields in new_index_together}
  329. # Deleted indexes
  330. for fields in olds.difference(news):
  331. self._delete_composed_index(model, fields, {'index': True}, self.sql_delete_index)
  332. # Created indexes
  333. for field_names in news.difference(olds):
  334. fields = [model._meta.get_field(field) for field in field_names]
  335. self.execute(self._create_index_sql(model, fields, suffix="_idx"))
  336. def _delete_composed_index(self, model, fields, constraint_kwargs, sql):
  337. columns = [model._meta.get_field(field).column for field in fields]
  338. constraint_names = self._constraint_names(model, columns, **constraint_kwargs)
  339. if len(constraint_names) != 1:
  340. raise ValueError("Found wrong number (%s) of constraints for %s(%s)" % (
  341. len(constraint_names),
  342. model._meta.db_table,
  343. ", ".join(columns),
  344. ))
  345. self.execute(self._delete_constraint_sql(sql, model, constraint_names[0]))
  346. def alter_db_table(self, model, old_db_table, new_db_table):
  347. """Rename the table a model points to."""
  348. if (old_db_table == new_db_table or
  349. (self.connection.features.ignores_table_name_case and
  350. old_db_table.lower() == new_db_table.lower())):
  351. return
  352. self.execute(self.sql_rename_table % {
  353. "old_table": self.quote_name(old_db_table),
  354. "new_table": self.quote_name(new_db_table),
  355. })
  356. # Rename all references to the old table name.
  357. for sql in self.deferred_sql:
  358. if isinstance(sql, Statement):
  359. sql.rename_table_references(old_db_table, new_db_table)
  360. def alter_db_tablespace(self, model, old_db_tablespace, new_db_tablespace):
  361. """Move a model's table between tablespaces."""
  362. self.execute(self.sql_retablespace_table % {
  363. "table": self.quote_name(model._meta.db_table),
  364. "old_tablespace": self.quote_name(old_db_tablespace),
  365. "new_tablespace": self.quote_name(new_db_tablespace),
  366. })
  367. def add_field(self, model, field):
  368. """
  369. Create a field on a model. Usually involves adding a column, but may
  370. involve adding a table instead (for M2M fields).
  371. """
  372. # Special-case implicit M2M tables
  373. if field.many_to_many and field.remote_field.through._meta.auto_created:
  374. return self.create_model(field.remote_field.through)
  375. # Get the column's definition
  376. definition, params = self.column_sql(model, field, include_default=True)
  377. # It might not actually have a column behind it
  378. if definition is None:
  379. return
  380. # Check constraints can go on the column SQL here
  381. db_params = field.db_parameters(connection=self.connection)
  382. if db_params['check']:
  383. definition += " CHECK (%s)" % db_params['check']
  384. # Build the SQL and run it
  385. sql = self.sql_create_column % {
  386. "table": self.quote_name(model._meta.db_table),
  387. "column": self.quote_name(field.column),
  388. "definition": definition,
  389. }
  390. self.execute(sql, params)
  391. # Drop the default if we need to
  392. # (Django usually does not use in-database defaults)
  393. if not self.skip_default(field) and self.effective_default(field) is not None:
  394. changes_sql, params = self._alter_column_default_sql(model, None, field, drop=True)
  395. sql = self.sql_alter_column % {
  396. "table": self.quote_name(model._meta.db_table),
  397. "changes": changes_sql,
  398. }
  399. self.execute(sql, params)
  400. # Add an index, if required
  401. self.deferred_sql.extend(self._field_indexes_sql(model, field))
  402. # Add any FK constraints later
  403. if field.remote_field and self.connection.features.supports_foreign_keys and field.db_constraint:
  404. self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
  405. # Reset connection if required
  406. if self.connection.features.connection_persists_old_columns:
  407. self.connection.close()
  408. def remove_field(self, model, field):
  409. """
  410. Remove a field from a model. Usually involves deleting a column,
  411. but for M2Ms may involve deleting a table.
  412. """
  413. # Special-case implicit M2M tables
  414. if field.many_to_many and field.remote_field.through._meta.auto_created:
  415. return self.delete_model(field.remote_field.through)
  416. # It might not actually have a column behind it
  417. if field.db_parameters(connection=self.connection)['type'] is None:
  418. return
  419. # Drop any FK constraints, MySQL requires explicit deletion
  420. if field.remote_field:
  421. fk_names = self._constraint_names(model, [field.column], foreign_key=True)
  422. for fk_name in fk_names:
  423. self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
  424. # Delete the column
  425. sql = self.sql_delete_column % {
  426. "table": self.quote_name(model._meta.db_table),
  427. "column": self.quote_name(field.column),
  428. }
  429. self.execute(sql)
  430. # Reset connection if required
  431. if self.connection.features.connection_persists_old_columns:
  432. self.connection.close()
  433. # Remove all deferred statements referencing the deleted column.
  434. for sql in list(self.deferred_sql):
  435. if isinstance(sql, Statement) and sql.references_column(model._meta.db_table, field.column):
  436. self.deferred_sql.remove(sql)
  437. def alter_field(self, model, old_field, new_field, strict=False):
  438. """
  439. Allow a field's type, uniqueness, nullability, default, column,
  440. constraints, etc. to be modified.
  441. `old_field` is required to compute the necessary changes.
  442. If `strict` is True, raise errors if the old column does not match
  443. `old_field` precisely.
  444. """
  445. # Ensure this field is even column-based
  446. old_db_params = old_field.db_parameters(connection=self.connection)
  447. old_type = old_db_params['type']
  448. new_db_params = new_field.db_parameters(connection=self.connection)
  449. new_type = new_db_params['type']
  450. if ((old_type is None and old_field.remote_field is None) or
  451. (new_type is None and new_field.remote_field is None)):
  452. raise ValueError(
  453. "Cannot alter field %s into %s - they do not properly define "
  454. "db_type (are you using a badly-written custom field?)" %
  455. (old_field, new_field),
  456. )
  457. elif old_type is None and new_type is None and (
  458. old_field.remote_field.through and new_field.remote_field.through and
  459. old_field.remote_field.through._meta.auto_created and
  460. new_field.remote_field.through._meta.auto_created):
  461. return self._alter_many_to_many(model, old_field, new_field, strict)
  462. elif old_type is None and new_type is None and (
  463. old_field.remote_field.through and new_field.remote_field.through and
  464. not old_field.remote_field.through._meta.auto_created and
  465. not new_field.remote_field.through._meta.auto_created):
  466. # Both sides have through models; this is a no-op.
  467. return
  468. elif old_type is None or new_type is None:
  469. raise ValueError(
  470. "Cannot alter field %s into %s - they are not compatible types "
  471. "(you cannot alter to or from M2M fields, or add or remove "
  472. "through= on M2M fields)" % (old_field, new_field)
  473. )
  474. self._alter_field(model, old_field, new_field, old_type, new_type,
  475. old_db_params, new_db_params, strict)
  476. def _alter_field(self, model, old_field, new_field, old_type, new_type,
  477. old_db_params, new_db_params, strict=False):
  478. """Perform a "physical" (non-ManyToMany) field update."""
  479. # Drop any FK constraints, we'll remake them later
  480. fks_dropped = set()
  481. if old_field.remote_field and old_field.db_constraint:
  482. fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
  483. if strict and len(fk_names) != 1:
  484. raise ValueError("Found wrong number (%s) of foreign key constraints for %s.%s" % (
  485. len(fk_names),
  486. model._meta.db_table,
  487. old_field.column,
  488. ))
  489. for fk_name in fk_names:
  490. fks_dropped.add((old_field.column,))
  491. self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
  492. # Has unique been removed?
  493. if old_field.unique and (not new_field.unique or self._field_became_primary_key(old_field, new_field)):
  494. # Find the unique constraint for this field
  495. constraint_names = self._constraint_names(model, [old_field.column], unique=True, primary_key=False)
  496. if strict and len(constraint_names) != 1:
  497. raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
  498. len(constraint_names),
  499. model._meta.db_table,
  500. old_field.column,
  501. ))
  502. for constraint_name in constraint_names:
  503. self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
  504. # Drop incoming FK constraints if the field is a primary key or unique,
  505. # which might be a to_field target, and things are going to change.
  506. drop_foreign_keys = (
  507. (
  508. (old_field.primary_key and new_field.primary_key) or
  509. (old_field.unique and new_field.unique)
  510. ) and old_type != new_type
  511. )
  512. if drop_foreign_keys:
  513. # '_meta.related_field' also contains M2M reverse fields, these
  514. # will be filtered out
  515. for _old_rel, new_rel in _related_non_m2m_objects(old_field, new_field):
  516. rel_fk_names = self._constraint_names(
  517. new_rel.related_model, [new_rel.field.column], foreign_key=True
  518. )
  519. for fk_name in rel_fk_names:
  520. self.execute(self._delete_constraint_sql(self.sql_delete_fk, new_rel.related_model, fk_name))
  521. # Removed an index? (no strict check, as multiple indexes are possible)
  522. # Remove indexes if db_index switched to False or a unique constraint
  523. # will now be used in lieu of an index. The following lines from the
  524. # truth table show all True cases; the rest are False:
  525. #
  526. # old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
  527. # ------------------------------------------------------------------------------
  528. # True | False | False | False
  529. # True | False | False | True
  530. # True | False | True | True
  531. if old_field.db_index and not old_field.unique and (not new_field.db_index or new_field.unique):
  532. # Find the index for this field
  533. meta_index_names = {index.name for index in model._meta.indexes}
  534. # Retrieve only BTREE indexes since this is what's created with
  535. # db_index=True.
  536. index_names = self._constraint_names(model, [old_field.column], index=True, type_=Index.suffix)
  537. for index_name in index_names:
  538. if index_name not in meta_index_names:
  539. # The only way to check if an index was created with
  540. # db_index=True or with Index(['field'], name='foo')
  541. # is to look at its name (refs #28053).
  542. self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
  543. # Change check constraints?
  544. if old_db_params['check'] != new_db_params['check'] and old_db_params['check']:
  545. constraint_names = self._constraint_names(model, [old_field.column], check=True)
  546. if strict and len(constraint_names) != 1:
  547. raise ValueError("Found wrong number (%s) of check constraints for %s.%s" % (
  548. len(constraint_names),
  549. model._meta.db_table,
  550. old_field.column,
  551. ))
  552. for constraint_name in constraint_names:
  553. self.execute(self._delete_constraint_sql(self.sql_delete_check, model, constraint_name))
  554. # Have they renamed the column?
  555. if old_field.column != new_field.column:
  556. self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type))
  557. # Rename all references to the renamed column.
  558. for sql in self.deferred_sql:
  559. if isinstance(sql, Statement):
  560. sql.rename_column_references(model._meta.db_table, old_field.column, new_field.column)
  561. # Next, start accumulating actions to do
  562. actions = []
  563. null_actions = []
  564. post_actions = []
  565. # Type change?
  566. if old_type != new_type:
  567. fragment, other_actions = self._alter_column_type_sql(model, old_field, new_field, new_type)
  568. actions.append(fragment)
  569. post_actions.extend(other_actions)
  570. # When changing a column NULL constraint to NOT NULL with a given
  571. # default value, we need to perform 4 steps:
  572. # 1. Add a default for new incoming writes
  573. # 2. Update existing NULL rows with new default
  574. # 3. Replace NULL constraint with NOT NULL
  575. # 4. Drop the default again.
  576. # Default change?
  577. old_default = self.effective_default(old_field)
  578. new_default = self.effective_default(new_field)
  579. needs_database_default = (
  580. old_field.null and
  581. not new_field.null and
  582. old_default != new_default and
  583. new_default is not None and
  584. not self.skip_default(new_field)
  585. )
  586. if needs_database_default:
  587. actions.append(self._alter_column_default_sql(model, old_field, new_field))
  588. # Nullability change?
  589. if old_field.null != new_field.null:
  590. fragment = self._alter_column_null_sql(model, old_field, new_field)
  591. if fragment:
  592. null_actions.append(fragment)
  593. # Only if we have a default and there is a change from NULL to NOT NULL
  594. four_way_default_alteration = (
  595. new_field.has_default() and
  596. (old_field.null and not new_field.null)
  597. )
  598. if actions or null_actions:
  599. if not four_way_default_alteration:
  600. # If we don't have to do a 4-way default alteration we can
  601. # directly run a (NOT) NULL alteration
  602. actions = actions + null_actions
  603. # Combine actions together if we can (e.g. postgres)
  604. if self.connection.features.supports_combined_alters and actions:
  605. sql, params = tuple(zip(*actions))
  606. actions = [(", ".join(sql), sum(params, []))]
  607. # Apply those actions
  608. for sql, params in actions:
  609. self.execute(
  610. self.sql_alter_column % {
  611. "table": self.quote_name(model._meta.db_table),
  612. "changes": sql,
  613. },
  614. params,
  615. )
  616. if four_way_default_alteration:
  617. # Update existing rows with default value
  618. self.execute(
  619. self.sql_update_with_default % {
  620. "table": self.quote_name(model._meta.db_table),
  621. "column": self.quote_name(new_field.column),
  622. "default": "%s",
  623. },
  624. [new_default],
  625. )
  626. # Since we didn't run a NOT NULL change before we need to do it
  627. # now
  628. for sql, params in null_actions:
  629. self.execute(
  630. self.sql_alter_column % {
  631. "table": self.quote_name(model._meta.db_table),
  632. "changes": sql,
  633. },
  634. params,
  635. )
  636. if post_actions:
  637. for sql, params in post_actions:
  638. self.execute(sql, params)
  639. # If primary_key changed to False, delete the primary key constraint.
  640. if old_field.primary_key and not new_field.primary_key:
  641. self._delete_primary_key(model, strict)
  642. # Added a unique?
  643. if self._unique_should_be_added(old_field, new_field):
  644. self.execute(self._create_unique_sql(model, [new_field.column]))
  645. # Added an index? Add an index if db_index switched to True or a unique
  646. # constraint will no longer be used in lieu of an index. The following
  647. # lines from the truth table show all True cases; the rest are False:
  648. #
  649. # old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
  650. # ------------------------------------------------------------------------------
  651. # False | False | True | False
  652. # False | True | True | False
  653. # True | True | True | False
  654. if (not old_field.db_index or old_field.unique) and new_field.db_index and not new_field.unique:
  655. self.execute(self._create_index_sql(model, [new_field]))
  656. # Type alteration on primary key? Then we need to alter the column
  657. # referring to us.
  658. rels_to_update = []
  659. if old_field.primary_key and new_field.primary_key and old_type != new_type:
  660. rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
  661. # Changed to become primary key?
  662. if self._field_became_primary_key(old_field, new_field):
  663. # Make the new one
  664. self.execute(
  665. self.sql_create_pk % {
  666. "table": self.quote_name(model._meta.db_table),
  667. "name": self.quote_name(
  668. self._create_index_name(model._meta.db_table, [new_field.column], suffix="_pk")
  669. ),
  670. "columns": self.quote_name(new_field.column),
  671. }
  672. )
  673. # Update all referencing columns
  674. rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
  675. # Handle our type alters on the other end of rels from the PK stuff above
  676. for old_rel, new_rel in rels_to_update:
  677. rel_db_params = new_rel.field.db_parameters(connection=self.connection)
  678. rel_type = rel_db_params['type']
  679. fragment, other_actions = self._alter_column_type_sql(
  680. new_rel.related_model, old_rel.field, new_rel.field, rel_type
  681. )
  682. self.execute(
  683. self.sql_alter_column % {
  684. "table": self.quote_name(new_rel.related_model._meta.db_table),
  685. "changes": fragment[0],
  686. },
  687. fragment[1],
  688. )
  689. for sql, params in other_actions:
  690. self.execute(sql, params)
  691. # Does it have a foreign key?
  692. if (new_field.remote_field and
  693. (fks_dropped or not old_field.remote_field or not old_field.db_constraint) and
  694. new_field.db_constraint):
  695. self.execute(self._create_fk_sql(model, new_field, "_fk_%(to_table)s_%(to_column)s"))
  696. # Rebuild FKs that pointed to us if we previously had to drop them
  697. if drop_foreign_keys:
  698. for rel in new_field.model._meta.related_objects:
  699. if _is_relevant_relation(rel, new_field) and rel.field.db_constraint:
  700. self.execute(self._create_fk_sql(rel.related_model, rel.field, "_fk"))
  701. # Does it have check constraints we need to add?
  702. if old_db_params['check'] != new_db_params['check'] and new_db_params['check']:
  703. self.execute(
  704. self.sql_create_check % {
  705. "table": self.quote_name(model._meta.db_table),
  706. "name": self.quote_name(
  707. self._create_index_name(model._meta.db_table, [new_field.column], suffix="_check")
  708. ),
  709. "column": self.quote_name(new_field.column),
  710. "check": new_db_params['check'],
  711. }
  712. )
  713. # Drop the default if we need to
  714. # (Django usually does not use in-database defaults)
  715. if needs_database_default:
  716. changes_sql, params = self._alter_column_default_sql(model, old_field, new_field, drop=True)
  717. sql = self.sql_alter_column % {
  718. "table": self.quote_name(model._meta.db_table),
  719. "changes": changes_sql,
  720. }
  721. self.execute(sql, params)
  722. # Reset connection if required
  723. if self.connection.features.connection_persists_old_columns:
  724. self.connection.close()
  725. def _alter_column_null_sql(self, model, old_field, new_field):
  726. """
  727. Hook to specialize column null alteration.
  728. Return a (sql, params) fragment to set a column to null or non-null
  729. as required by new_field, or None if no changes are required.
  730. """
  731. if (self.connection.features.interprets_empty_strings_as_nulls and
  732. new_field.get_internal_type() in ("CharField", "TextField")):
  733. # The field is nullable in the database anyway, leave it alone.
  734. return
  735. else:
  736. new_db_params = new_field.db_parameters(connection=self.connection)
  737. sql = self.sql_alter_column_null if new_field.null else self.sql_alter_column_not_null
  738. return (
  739. sql % {
  740. 'column': self.quote_name(new_field.column),
  741. 'type': new_db_params['type'],
  742. },
  743. [],
  744. )
  745. def _alter_column_default_sql(self, model, old_field, new_field, drop=False):
  746. """
  747. Hook to specialize column default alteration.
  748. Return a (sql, params) fragment to add or drop (depending on the drop
  749. argument) a default to new_field's column.
  750. """
  751. new_default = self.effective_default(new_field)
  752. default = '%s'
  753. params = [new_default]
  754. if drop:
  755. params = []
  756. elif self.connection.features.requires_literal_defaults:
  757. # Some databases (Oracle) can't take defaults as a parameter
  758. # If this is the case, the SchemaEditor for that database should
  759. # implement prepare_default().
  760. default = self.prepare_default(new_default)
  761. params = []
  762. new_db_params = new_field.db_parameters(connection=self.connection)
  763. sql = self.sql_alter_column_no_default if drop else self.sql_alter_column_default
  764. return (
  765. sql % {
  766. 'column': self.quote_name(new_field.column),
  767. 'type': new_db_params['type'],
  768. 'default': default,
  769. },
  770. params,
  771. )
  772. def _alter_column_type_sql(self, model, old_field, new_field, new_type):
  773. """
  774. Hook to specialize column type alteration for different backends,
  775. for cases when a creation type is different to an alteration type
  776. (e.g. SERIAL in PostgreSQL, PostGIS fields).
  777. Return a two-tuple of: an SQL fragment of (sql, params) to insert into
  778. an ALTER TABLE statement and a list of extra (sql, params) tuples to
  779. run once the field is altered.
  780. """
  781. return (
  782. (
  783. self.sql_alter_column_type % {
  784. "column": self.quote_name(new_field.column),
  785. "type": new_type,
  786. },
  787. [],
  788. ),
  789. [],
  790. )
  791. def _alter_many_to_many(self, model, old_field, new_field, strict):
  792. """Alter M2Ms to repoint their to= endpoints."""
  793. # Rename the through table
  794. if old_field.remote_field.through._meta.db_table != new_field.remote_field.through._meta.db_table:
  795. self.alter_db_table(old_field.remote_field.through, old_field.remote_field.through._meta.db_table,
  796. new_field.remote_field.through._meta.db_table)
  797. # Repoint the FK to the other side
  798. self.alter_field(
  799. new_field.remote_field.through,
  800. # We need the field that points to the target model, so we can tell alter_field to change it -
  801. # this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model)
  802. old_field.remote_field.through._meta.get_field(old_field.m2m_reverse_field_name()),
  803. new_field.remote_field.through._meta.get_field(new_field.m2m_reverse_field_name()),
  804. )
  805. self.alter_field(
  806. new_field.remote_field.through,
  807. # for self-referential models we need to alter field from the other end too
  808. old_field.remote_field.through._meta.get_field(old_field.m2m_field_name()),
  809. new_field.remote_field.through._meta.get_field(new_field.m2m_field_name()),
  810. )
  811. def _create_index_name(self, table_name, column_names, suffix=""):
  812. """
  813. Generate a unique name for an index/unique constraint.
  814. The name is divided into 3 parts: the table name, the column names,
  815. and a unique digest and suffix.
  816. """
  817. _, table_name = split_identifier(table_name)
  818. hash_suffix_part = '%s%s' % (self._digest(table_name, *column_names), suffix)
  819. max_length = self.connection.ops.max_name_length() or 200
  820. # If everything fits into max_length, use that name.
  821. index_name = '%s_%s_%s' % (table_name, '_'.join(column_names), hash_suffix_part)
  822. if len(index_name) <= max_length:
  823. return index_name
  824. # Shorten a long suffix.
  825. if len(hash_suffix_part) > max_length / 3:
  826. hash_suffix_part = hash_suffix_part[:max_length // 3]
  827. other_length = (max_length - len(hash_suffix_part)) // 2 - 1
  828. index_name = '%s_%s_%s' % (
  829. table_name[:other_length],
  830. '_'.join(column_names)[:other_length],
  831. hash_suffix_part,
  832. )
  833. # Prepend D if needed to prevent the name from starting with an
  834. # underscore or a number (not permitted on Oracle).
  835. if index_name[0] == "_" or index_name[0].isdigit():
  836. index_name = "D%s" % index_name[:-1]
  837. return index_name
  838. def _get_index_tablespace_sql(self, model, fields, db_tablespace=None):
  839. if db_tablespace is None:
  840. if len(fields) == 1 and fields[0].db_tablespace:
  841. db_tablespace = fields[0].db_tablespace
  842. elif model._meta.db_tablespace:
  843. db_tablespace = model._meta.db_tablespace
  844. if db_tablespace is not None:
  845. return ' ' + self.connection.ops.tablespace_sql(db_tablespace)
  846. return ''
  847. def _create_index_sql(self, model, fields, *, name=None, suffix='', using='',
  848. db_tablespace=None, col_suffixes=(), sql=None):
  849. """
  850. Return the SQL statement to create the index for one or several fields.
  851. `sql` can be specified if the syntax differs from the standard (GIS
  852. indexes, ...).
  853. """
  854. tablespace_sql = self._get_index_tablespace_sql(model, fields, db_tablespace=db_tablespace)
  855. columns = [field.column for field in fields]
  856. sql_create_index = sql or self.sql_create_index
  857. table = model._meta.db_table
  858. def create_index_name(*args, **kwargs):
  859. nonlocal name
  860. if name is None:
  861. name = self._create_index_name(*args, **kwargs)
  862. return self.quote_name(name)
  863. return Statement(
  864. sql_create_index,
  865. table=Table(table, self.quote_name),
  866. name=IndexName(table, columns, suffix, create_index_name),
  867. using=using,
  868. columns=Columns(table, columns, self.quote_name, col_suffixes=col_suffixes),
  869. extra=tablespace_sql,
  870. )
  871. def _model_indexes_sql(self, model):
  872. """
  873. Return a list of all index SQL statements (field indexes,
  874. index_together, Meta.indexes) for the specified model.
  875. """
  876. if not model._meta.managed or model._meta.proxy or model._meta.swapped:
  877. return []
  878. output = []
  879. for field in model._meta.local_fields:
  880. output.extend(self._field_indexes_sql(model, field))
  881. for field_names in model._meta.index_together:
  882. fields = [model._meta.get_field(field) for field in field_names]
  883. output.append(self._create_index_sql(model, fields, suffix="_idx"))
  884. for index in model._meta.indexes:
  885. output.append(index.create_sql(model, self))
  886. return output
  887. def _field_indexes_sql(self, model, field):
  888. """
  889. Return a list of all index SQL statements for the specified field.
  890. """
  891. output = []
  892. if self._field_should_be_indexed(model, field):
  893. output.append(self._create_index_sql(model, [field]))
  894. return output
  895. def _field_should_be_indexed(self, model, field):
  896. return field.db_index and not field.unique
  897. def _field_became_primary_key(self, old_field, new_field):
  898. return not old_field.primary_key and new_field.primary_key
  899. def _unique_should_be_added(self, old_field, new_field):
  900. return (not old_field.unique and new_field.unique) or (
  901. old_field.primary_key and not new_field.primary_key and new_field.unique
  902. )
  903. def _rename_field_sql(self, table, old_field, new_field, new_type):
  904. return self.sql_rename_column % {
  905. "table": self.quote_name(table),
  906. "old_column": self.quote_name(old_field.column),
  907. "new_column": self.quote_name(new_field.column),
  908. "type": new_type,
  909. }
  910. def _create_fk_sql(self, model, field, suffix):
  911. from_table = model._meta.db_table
  912. from_column = field.column
  913. _, to_table = split_identifier(field.target_field.model._meta.db_table)
  914. to_column = field.target_field.column
  915. def create_fk_name(*args, **kwargs):
  916. return self.quote_name(self._create_index_name(*args, **kwargs))
  917. return Statement(
  918. self.sql_create_fk,
  919. table=Table(from_table, self.quote_name),
  920. name=ForeignKeyName(from_table, [from_column], to_table, [to_column], suffix, create_fk_name),
  921. column=Columns(from_table, [from_column], self.quote_name),
  922. to_table=Table(field.target_field.model._meta.db_table, self.quote_name),
  923. to_column=Columns(field.target_field.model._meta.db_table, [to_column], self.quote_name),
  924. deferrable=self.connection.ops.deferrable_sql(),
  925. )
  926. def _create_unique_sql(self, model, columns):
  927. def create_unique_name(*args, **kwargs):
  928. return self.quote_name(self._create_index_name(*args, **kwargs))
  929. table = model._meta.db_table
  930. return Statement(
  931. self.sql_create_unique,
  932. table=Table(table, self.quote_name),
  933. name=IndexName(table, columns, '_uniq', create_unique_name),
  934. columns=Columns(table, columns, self.quote_name),
  935. )
  936. def _delete_constraint_sql(self, template, model, name):
  937. return template % {
  938. "table": self.quote_name(model._meta.db_table),
  939. "name": self.quote_name(name),
  940. }
  941. def _constraint_names(self, model, column_names=None, unique=None,
  942. primary_key=None, index=None, foreign_key=None,
  943. check=None, type_=None):
  944. """Return all constraint names matching the columns and conditions."""
  945. if column_names is not None:
  946. column_names = [
  947. self.connection.introspection.column_name_converter(name)
  948. for name in column_names
  949. ]
  950. with self.connection.cursor() as cursor:
  951. constraints = self.connection.introspection.get_constraints(cursor, model._meta.db_table)
  952. result = []
  953. for name, infodict in constraints.items():
  954. if column_names is None or column_names == infodict['columns']:
  955. if unique is not None and infodict['unique'] != unique:
  956. continue
  957. if primary_key is not None and infodict['primary_key'] != primary_key:
  958. continue
  959. if index is not None and infodict['index'] != index:
  960. continue
  961. if check is not None and infodict['check'] != check:
  962. continue
  963. if foreign_key is not None and not infodict['foreign_key']:
  964. continue
  965. if type_ is not None and infodict['type'] != type_:
  966. continue
  967. result.append(name)
  968. return result
  969. def _delete_primary_key(self, model, strict=False):
  970. constraint_names = self._constraint_names(model, primary_key=True)
  971. if strict and len(constraint_names) != 1:
  972. raise ValueError('Found wrong number (%s) of PK constraints for %s' % (
  973. len(constraint_names),
  974. model._meta.db_table,
  975. ))
  976. for constraint_name in constraint_names:
  977. self.execute(self._delete_constraint_sql(self.sql_delete_pk, model, constraint_name))
  978. def remove_procedure(self, procedure_name, param_types=()):
  979. sql = self.sql_delete_procedure % {
  980. 'procedure': self.quote_name(procedure_name),
  981. 'param_types': ','.join(param_types),
  982. }
  983. self.execute(sql)