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.
 
 
 
 

1173 lines
55 KiB

  1. from __future__ import unicode_literals
  2. import datetime
  3. import functools
  4. import re
  5. from itertools import chain
  6. from django.conf import settings
  7. from django.db import models
  8. from django.db.migrations import operations
  9. from django.db.migrations.migration import Migration
  10. from django.db.migrations.operations.models import AlterModelOptions
  11. from django.db.migrations.optimizer import MigrationOptimizer
  12. from django.db.migrations.questioner import MigrationQuestioner
  13. from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
  14. from django.utils import six
  15. from .topological_sort import stable_topological_sort
  16. class MigrationAutodetector(object):
  17. """
  18. Takes a pair of ProjectStates, and compares them to see what the
  19. first would need doing to make it match the second (the second
  20. usually being the project's current state).
  21. Note that this naturally operates on entire projects at a time,
  22. as it's likely that changes interact (for example, you can't
  23. add a ForeignKey without having a migration to add the table it
  24. depends on first). A user interface may offer single-app usage
  25. if it wishes, with the caveat that it may not always be possible.
  26. """
  27. def __init__(self, from_state, to_state, questioner=None):
  28. self.from_state = from_state
  29. self.to_state = to_state
  30. self.questioner = questioner or MigrationQuestioner()
  31. self.existing_apps = {app for app, model in from_state.models}
  32. def changes(self, graph, trim_to_apps=None, convert_apps=None, migration_name=None):
  33. """
  34. Main entry point to produce a list of applicable changes.
  35. Takes a graph to base names on and an optional set of apps
  36. to try and restrict to (restriction is not guaranteed)
  37. """
  38. changes = self._detect_changes(convert_apps, graph)
  39. changes = self.arrange_for_graph(changes, graph, migration_name)
  40. if trim_to_apps:
  41. changes = self._trim_to_apps(changes, trim_to_apps)
  42. return changes
  43. def deep_deconstruct(self, obj):
  44. """
  45. Recursive deconstruction for a field and its arguments.
  46. Used for full comparison for rename/alter; sometimes a single-level
  47. deconstruction will not compare correctly.
  48. """
  49. if isinstance(obj, list):
  50. return [self.deep_deconstruct(value) for value in obj]
  51. elif isinstance(obj, tuple):
  52. return tuple(self.deep_deconstruct(value) for value in obj)
  53. elif isinstance(obj, dict):
  54. return {
  55. key: self.deep_deconstruct(value)
  56. for key, value in obj.items()
  57. }
  58. elif isinstance(obj, functools.partial):
  59. return (obj.func, self.deep_deconstruct(obj.args), self.deep_deconstruct(obj.keywords))
  60. elif isinstance(obj, COMPILED_REGEX_TYPE):
  61. return RegexObject(obj)
  62. elif isinstance(obj, type):
  63. # If this is a type that implements 'deconstruct' as an instance method,
  64. # avoid treating this as being deconstructible itself - see #22951
  65. return obj
  66. elif hasattr(obj, 'deconstruct'):
  67. deconstructed = obj.deconstruct()
  68. if isinstance(obj, models.Field):
  69. # we have a field which also returns a name
  70. deconstructed = deconstructed[1:]
  71. path, args, kwargs = deconstructed
  72. return (
  73. path,
  74. [self.deep_deconstruct(value) for value in args],
  75. {
  76. key: self.deep_deconstruct(value)
  77. for key, value in kwargs.items()
  78. },
  79. )
  80. else:
  81. return obj
  82. def only_relation_agnostic_fields(self, fields):
  83. """
  84. Return a definition of the fields that ignores field names and
  85. what related fields actually relate to.
  86. Used for detecting renames (as, of course, the related fields
  87. change during renames)
  88. """
  89. fields_def = []
  90. for name, field in sorted(fields):
  91. deconstruction = self.deep_deconstruct(field)
  92. if field.remote_field and field.remote_field.model:
  93. del deconstruction[2]['to']
  94. fields_def.append(deconstruction)
  95. return fields_def
  96. def _detect_changes(self, convert_apps=None, graph=None):
  97. """
  98. Returns a dict of migration plans which will achieve the
  99. change from from_state to to_state. The dict has app labels
  100. as keys and a list of migrations as values.
  101. The resulting migrations aren't specially named, but the names
  102. do matter for dependencies inside the set.
  103. convert_apps is the list of apps to convert to use migrations
  104. (i.e. to make initial migrations for, in the usual case)
  105. graph is an optional argument that, if provided, can help improve
  106. dependency generation and avoid potential circular dependencies.
  107. """
  108. # The first phase is generating all the operations for each app
  109. # and gathering them into a big per-app list.
  110. # We'll then go through that list later and order it and split
  111. # into migrations to resolve dependencies caused by M2Ms and FKs.
  112. self.generated_operations = {}
  113. # Prepare some old/new state and model lists, separating
  114. # proxy models and ignoring unmigrated apps.
  115. self.old_apps = self.from_state.concrete_apps
  116. self.new_apps = self.to_state.apps
  117. self.old_model_keys = []
  118. self.old_proxy_keys = []
  119. self.old_unmanaged_keys = []
  120. self.new_model_keys = []
  121. self.new_proxy_keys = []
  122. self.new_unmanaged_keys = []
  123. for al, mn in sorted(self.from_state.models.keys()):
  124. model = self.old_apps.get_model(al, mn)
  125. if not model._meta.managed:
  126. self.old_unmanaged_keys.append((al, mn))
  127. elif al not in self.from_state.real_apps:
  128. if model._meta.proxy:
  129. self.old_proxy_keys.append((al, mn))
  130. else:
  131. self.old_model_keys.append((al, mn))
  132. for al, mn in sorted(self.to_state.models.keys()):
  133. model = self.new_apps.get_model(al, mn)
  134. if not model._meta.managed:
  135. self.new_unmanaged_keys.append((al, mn))
  136. elif (
  137. al not in self.from_state.real_apps or
  138. (convert_apps and al in convert_apps)
  139. ):
  140. if model._meta.proxy:
  141. self.new_proxy_keys.append((al, mn))
  142. else:
  143. self.new_model_keys.append((al, mn))
  144. # Renames have to come first
  145. self.generate_renamed_models()
  146. # Prepare lists of fields and generate through model map
  147. self._prepare_field_lists()
  148. self._generate_through_model_map()
  149. # Generate non-rename model operations
  150. self.generate_deleted_models()
  151. self.generate_created_models()
  152. self.generate_deleted_proxies()
  153. self.generate_created_proxies()
  154. self.generate_altered_options()
  155. self.generate_altered_managers()
  156. # Generate field operations
  157. self.generate_renamed_fields()
  158. self.generate_removed_fields()
  159. self.generate_added_fields()
  160. self.generate_altered_fields()
  161. self.generate_altered_unique_together()
  162. self.generate_altered_index_together()
  163. self.generate_altered_db_table()
  164. self.generate_altered_order_with_respect_to()
  165. self._sort_migrations()
  166. self._build_migration_list(graph)
  167. self._optimize_migrations()
  168. return self.migrations
  169. def _prepare_field_lists(self):
  170. """
  171. Prepare field lists, and prepare a list of the fields that used
  172. through models in the old state so we can make dependencies
  173. from the through model deletion to the field that uses it.
  174. """
  175. self.kept_model_keys = set(self.old_model_keys).intersection(self.new_model_keys)
  176. self.kept_proxy_keys = set(self.old_proxy_keys).intersection(self.new_proxy_keys)
  177. self.kept_unmanaged_keys = set(self.old_unmanaged_keys).intersection(self.new_unmanaged_keys)
  178. self.through_users = {}
  179. self.old_field_keys = set()
  180. self.new_field_keys = set()
  181. for app_label, model_name in sorted(self.kept_model_keys):
  182. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  183. old_model_state = self.from_state.models[app_label, old_model_name]
  184. new_model_state = self.to_state.models[app_label, model_name]
  185. self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields)
  186. self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields)
  187. def _generate_through_model_map(self):
  188. """
  189. Through model map generation
  190. """
  191. for app_label, model_name in sorted(self.old_model_keys):
  192. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  193. old_model_state = self.from_state.models[app_label, old_model_name]
  194. for field_name, field in old_model_state.fields:
  195. old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field(field_name)
  196. if (hasattr(old_field, "remote_field") and getattr(old_field.remote_field, "through", None)
  197. and not old_field.remote_field.through._meta.auto_created):
  198. through_key = (
  199. old_field.remote_field.through._meta.app_label,
  200. old_field.remote_field.through._meta.model_name,
  201. )
  202. self.through_users[through_key] = (app_label, old_model_name, field_name)
  203. def _build_migration_list(self, graph=None):
  204. """
  205. We need to chop the lists of operations up into migrations with
  206. dependencies on each other. We do this by stepping up an app's list of
  207. operations until we find one that has an outgoing dependency that isn't
  208. in another app's migration yet (hasn't been chopped off its list). We
  209. then chop off the operations before it into a migration and move onto
  210. the next app. If we loop back around without doing anything, there's a
  211. circular dependency (which _should_ be impossible as the operations are
  212. all split at this point so they can't depend and be depended on).
  213. """
  214. self.migrations = {}
  215. num_ops = sum(len(x) for x in self.generated_operations.values())
  216. chop_mode = False
  217. while num_ops:
  218. # On every iteration, we step through all the apps and see if there
  219. # is a completed set of operations.
  220. # If we find that a subset of the operations are complete we can
  221. # try to chop it off from the rest and continue, but we only
  222. # do this if we've already been through the list once before
  223. # without any chopping and nothing has changed.
  224. for app_label in sorted(self.generated_operations.keys()):
  225. chopped = []
  226. dependencies = set()
  227. for operation in list(self.generated_operations[app_label]):
  228. deps_satisfied = True
  229. operation_dependencies = set()
  230. for dep in operation._auto_deps:
  231. is_swappable_dep = False
  232. if dep[0] == "__setting__":
  233. # We need to temporarily resolve the swappable dependency to prevent
  234. # circular references. While keeping the dependency checks on the
  235. # resolved model we still add the swappable dependencies.
  236. # See #23322
  237. resolved_app_label, resolved_object_name = getattr(settings, dep[1]).split('.')
  238. original_dep = dep
  239. dep = (resolved_app_label, resolved_object_name.lower(), dep[2], dep[3])
  240. is_swappable_dep = True
  241. if dep[0] != app_label and dep[0] != "__setting__":
  242. # External app dependency. See if it's not yet
  243. # satisfied.
  244. for other_operation in self.generated_operations.get(dep[0], []):
  245. if self.check_dependency(other_operation, dep):
  246. deps_satisfied = False
  247. break
  248. if not deps_satisfied:
  249. break
  250. else:
  251. if is_swappable_dep:
  252. operation_dependencies.add((original_dep[0], original_dep[1]))
  253. elif dep[0] in self.migrations:
  254. operation_dependencies.add((dep[0], self.migrations[dep[0]][-1].name))
  255. else:
  256. # If we can't find the other app, we add a first/last dependency,
  257. # but only if we've already been through once and checked everything
  258. if chop_mode:
  259. # If the app already exists, we add a dependency on the last migration,
  260. # as we don't know which migration contains the target field.
  261. # If it's not yet migrated or has no migrations, we use __first__
  262. if graph and graph.leaf_nodes(dep[0]):
  263. operation_dependencies.add(graph.leaf_nodes(dep[0])[0])
  264. else:
  265. operation_dependencies.add((dep[0], "__first__"))
  266. else:
  267. deps_satisfied = False
  268. if deps_satisfied:
  269. chopped.append(operation)
  270. dependencies.update(operation_dependencies)
  271. self.generated_operations[app_label] = self.generated_operations[app_label][1:]
  272. else:
  273. break
  274. # Make a migration! Well, only if there's stuff to put in it
  275. if dependencies or chopped:
  276. if not self.generated_operations[app_label] or chop_mode:
  277. subclass = type(str("Migration"), (Migration,), {"operations": [], "dependencies": []})
  278. instance = subclass("auto_%i" % (len(self.migrations.get(app_label, [])) + 1), app_label)
  279. instance.dependencies = list(dependencies)
  280. instance.operations = chopped
  281. instance.initial = app_label not in self.existing_apps
  282. self.migrations.setdefault(app_label, []).append(instance)
  283. chop_mode = False
  284. else:
  285. self.generated_operations[app_label] = chopped + self.generated_operations[app_label]
  286. new_num_ops = sum(len(x) for x in self.generated_operations.values())
  287. if new_num_ops == num_ops:
  288. if not chop_mode:
  289. chop_mode = True
  290. else:
  291. raise ValueError("Cannot resolve operation dependencies: %r" % self.generated_operations)
  292. num_ops = new_num_ops
  293. def _sort_migrations(self):
  294. """
  295. Reorder to make things possible. The order we have already isn't bad,
  296. but we need to pull a few things around so FKs work nicely inside the
  297. same app
  298. """
  299. for app_label, ops in sorted(self.generated_operations.items()):
  300. # construct a dependency graph for intra-app dependencies
  301. dependency_graph = {op: set() for op in ops}
  302. for op in ops:
  303. for dep in op._auto_deps:
  304. if dep[0] == app_label:
  305. for op2 in ops:
  306. if self.check_dependency(op2, dep):
  307. dependency_graph[op].add(op2)
  308. # we use a stable sort for deterministic tests & general behavior
  309. self.generated_operations[app_label] = stable_topological_sort(ops, dependency_graph)
  310. def _optimize_migrations(self):
  311. # Add in internal dependencies among the migrations
  312. for app_label, migrations in self.migrations.items():
  313. for m1, m2 in zip(migrations, migrations[1:]):
  314. m2.dependencies.append((app_label, m1.name))
  315. # De-dupe dependencies
  316. for app_label, migrations in self.migrations.items():
  317. for migration in migrations:
  318. migration.dependencies = list(set(migration.dependencies))
  319. # Optimize migrations
  320. for app_label, migrations in self.migrations.items():
  321. for migration in migrations:
  322. migration.operations = MigrationOptimizer().optimize(migration.operations, app_label=app_label)
  323. def check_dependency(self, operation, dependency):
  324. """
  325. Returns ``True`` if the given operation depends on the given dependency,
  326. ``False`` otherwise.
  327. """
  328. # Created model
  329. if dependency[2] is None and dependency[3] is True:
  330. return (
  331. isinstance(operation, operations.CreateModel) and
  332. operation.name_lower == dependency[1].lower()
  333. )
  334. # Created field
  335. elif dependency[2] is not None and dependency[3] is True:
  336. return (
  337. (
  338. isinstance(operation, operations.CreateModel) and
  339. operation.name_lower == dependency[1].lower() and
  340. any(dependency[2] == x for x, y in operation.fields)
  341. ) or
  342. (
  343. isinstance(operation, operations.AddField) and
  344. operation.model_name_lower == dependency[1].lower() and
  345. operation.name_lower == dependency[2].lower()
  346. )
  347. )
  348. # Removed field
  349. elif dependency[2] is not None and dependency[3] is False:
  350. return (
  351. isinstance(operation, operations.RemoveField) and
  352. operation.model_name_lower == dependency[1].lower() and
  353. operation.name_lower == dependency[2].lower()
  354. )
  355. # Removed model
  356. elif dependency[2] is None and dependency[3] is False:
  357. return (
  358. isinstance(operation, operations.DeleteModel) and
  359. operation.name_lower == dependency[1].lower()
  360. )
  361. # Field being altered
  362. elif dependency[2] is not None and dependency[3] == "alter":
  363. return (
  364. isinstance(operation, operations.AlterField) and
  365. operation.model_name_lower == dependency[1].lower() and
  366. operation.name_lower == dependency[2].lower()
  367. )
  368. # order_with_respect_to being unset for a field
  369. elif dependency[2] is not None and dependency[3] == "order_wrt_unset":
  370. return (
  371. isinstance(operation, operations.AlterOrderWithRespectTo) and
  372. operation.name_lower == dependency[1].lower() and
  373. (operation.order_with_respect_to or "").lower() != dependency[2].lower()
  374. )
  375. # Field is removed and part of an index/unique_together
  376. elif dependency[2] is not None and dependency[3] == "foo_together_change":
  377. return (
  378. isinstance(operation, (operations.AlterUniqueTogether,
  379. operations.AlterIndexTogether)) and
  380. operation.name_lower == dependency[1].lower()
  381. )
  382. # Unknown dependency. Raise an error.
  383. else:
  384. raise ValueError("Can't handle dependency %r" % (dependency, ))
  385. def add_operation(self, app_label, operation, dependencies=None, beginning=False):
  386. # Dependencies are (app_label, model_name, field_name, create/delete as True/False)
  387. operation._auto_deps = dependencies or []
  388. if beginning:
  389. self.generated_operations.setdefault(app_label, []).insert(0, operation)
  390. else:
  391. self.generated_operations.setdefault(app_label, []).append(operation)
  392. def swappable_first_key(self, item):
  393. """
  394. Sorting key function that places potential swappable models first in
  395. lists of created models (only real way to solve #22783)
  396. """
  397. try:
  398. model = self.new_apps.get_model(item[0], item[1])
  399. base_names = [base.__name__ for base in model.__bases__]
  400. string_version = "%s.%s" % (item[0], item[1])
  401. if (
  402. model._meta.swappable or
  403. "AbstractUser" in base_names or
  404. "AbstractBaseUser" in base_names or
  405. settings.AUTH_USER_MODEL.lower() == string_version.lower()
  406. ):
  407. return ("___" + item[0], "___" + item[1])
  408. except LookupError:
  409. pass
  410. return item
  411. def generate_renamed_models(self):
  412. """
  413. Finds any renamed models, and generates the operations for them,
  414. and removes the old entry from the model lists.
  415. Must be run before other model-level generation.
  416. """
  417. self.renamed_models = {}
  418. self.renamed_models_rel = {}
  419. added_models = set(self.new_model_keys) - set(self.old_model_keys)
  420. for app_label, model_name in sorted(added_models):
  421. model_state = self.to_state.models[app_label, model_name]
  422. model_fields_def = self.only_relation_agnostic_fields(model_state.fields)
  423. removed_models = set(self.old_model_keys) - set(self.new_model_keys)
  424. for rem_app_label, rem_model_name in removed_models:
  425. if rem_app_label == app_label:
  426. rem_model_state = self.from_state.models[rem_app_label, rem_model_name]
  427. rem_model_fields_def = self.only_relation_agnostic_fields(rem_model_state.fields)
  428. if model_fields_def == rem_model_fields_def:
  429. if self.questioner.ask_rename_model(rem_model_state, model_state):
  430. self.add_operation(
  431. app_label,
  432. operations.RenameModel(
  433. old_name=rem_model_state.name,
  434. new_name=model_state.name,
  435. )
  436. )
  437. self.renamed_models[app_label, model_name] = rem_model_name
  438. renamed_models_rel_key = '%s.%s' % (rem_model_state.app_label, rem_model_state.name)
  439. self.renamed_models_rel[renamed_models_rel_key] = '%s.%s' % (
  440. model_state.app_label,
  441. model_state.name,
  442. )
  443. self.old_model_keys.remove((rem_app_label, rem_model_name))
  444. self.old_model_keys.append((app_label, model_name))
  445. break
  446. def generate_created_models(self):
  447. """
  448. Find all new models (both managed and unmanaged) and make create
  449. operations for them as well as separate operations to create any
  450. foreign key or M2M relationships (we'll optimize these back in later
  451. if we can).
  452. We also defer any model options that refer to collections of fields
  453. that might be deferred (e.g. unique_together, index_together).
  454. """
  455. old_keys = set(self.old_model_keys).union(self.old_unmanaged_keys)
  456. added_models = set(self.new_model_keys) - old_keys
  457. added_unmanaged_models = set(self.new_unmanaged_keys) - old_keys
  458. all_added_models = chain(
  459. sorted(added_models, key=self.swappable_first_key, reverse=True),
  460. sorted(added_unmanaged_models, key=self.swappable_first_key, reverse=True)
  461. )
  462. for app_label, model_name in all_added_models:
  463. model_state = self.to_state.models[app_label, model_name]
  464. model_opts = self.new_apps.get_model(app_label, model_name)._meta
  465. # Gather related fields
  466. related_fields = {}
  467. primary_key_rel = None
  468. for field in model_opts.local_fields:
  469. if field.remote_field:
  470. if field.remote_field.model:
  471. if field.primary_key:
  472. primary_key_rel = field.remote_field.model
  473. elif not field.remote_field.parent_link:
  474. related_fields[field.name] = field
  475. # through will be none on M2Ms on swapped-out models;
  476. # we can treat lack of through as auto_created=True, though.
  477. if (getattr(field.remote_field, "through", None)
  478. and not field.remote_field.through._meta.auto_created):
  479. related_fields[field.name] = field
  480. for field in model_opts.local_many_to_many:
  481. if field.remote_field.model:
  482. related_fields[field.name] = field
  483. if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
  484. related_fields[field.name] = field
  485. # Are there unique/index_together to defer?
  486. unique_together = model_state.options.pop('unique_together', None)
  487. index_together = model_state.options.pop('index_together', None)
  488. order_with_respect_to = model_state.options.pop('order_with_respect_to', None)
  489. # Depend on the deletion of any possible proxy version of us
  490. dependencies = [
  491. (app_label, model_name, None, False),
  492. ]
  493. # Depend on all bases
  494. for base in model_state.bases:
  495. if isinstance(base, six.string_types) and "." in base:
  496. base_app_label, base_name = base.split(".", 1)
  497. dependencies.append((base_app_label, base_name, None, True))
  498. # Depend on the other end of the primary key if it's a relation
  499. if primary_key_rel:
  500. dependencies.append((
  501. primary_key_rel._meta.app_label,
  502. primary_key_rel._meta.object_name,
  503. None,
  504. True
  505. ))
  506. # Generate creation operation
  507. self.add_operation(
  508. app_label,
  509. operations.CreateModel(
  510. name=model_state.name,
  511. fields=[d for d in model_state.fields if d[0] not in related_fields],
  512. options=model_state.options,
  513. bases=model_state.bases,
  514. managers=model_state.managers,
  515. ),
  516. dependencies=dependencies,
  517. beginning=True,
  518. )
  519. # Don't add operations which modify the database for unmanaged models
  520. if not model_opts.managed:
  521. continue
  522. # Generate operations for each related field
  523. for name, field in sorted(related_fields.items()):
  524. # Account for FKs to swappable models
  525. swappable_setting = getattr(field, 'swappable_setting', None)
  526. if swappable_setting is not None:
  527. dep_app_label = "__setting__"
  528. dep_object_name = swappable_setting
  529. else:
  530. dep_app_label = field.remote_field.model._meta.app_label
  531. dep_object_name = field.remote_field.model._meta.object_name
  532. dependencies = [(dep_app_label, dep_object_name, None, True)]
  533. if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
  534. dependencies.append((
  535. field.remote_field.through._meta.app_label,
  536. field.remote_field.through._meta.object_name,
  537. None,
  538. True
  539. ))
  540. # Depend on our own model being created
  541. dependencies.append((app_label, model_name, None, True))
  542. # Make operation
  543. self.add_operation(
  544. app_label,
  545. operations.AddField(
  546. model_name=model_name,
  547. name=name,
  548. field=field,
  549. ),
  550. dependencies=list(set(dependencies)),
  551. )
  552. # Generate other opns
  553. related_dependencies = [
  554. (app_label, model_name, name, True)
  555. for name, field in sorted(related_fields.items())
  556. ]
  557. related_dependencies.append((app_label, model_name, None, True))
  558. if unique_together:
  559. self.add_operation(
  560. app_label,
  561. operations.AlterUniqueTogether(
  562. name=model_name,
  563. unique_together=unique_together,
  564. ),
  565. dependencies=related_dependencies
  566. )
  567. if index_together:
  568. self.add_operation(
  569. app_label,
  570. operations.AlterIndexTogether(
  571. name=model_name,
  572. index_together=index_together,
  573. ),
  574. dependencies=related_dependencies
  575. )
  576. if order_with_respect_to:
  577. self.add_operation(
  578. app_label,
  579. operations.AlterOrderWithRespectTo(
  580. name=model_name,
  581. order_with_respect_to=order_with_respect_to,
  582. ),
  583. dependencies=[
  584. (app_label, model_name, order_with_respect_to, True),
  585. (app_label, model_name, None, True),
  586. ]
  587. )
  588. def generate_created_proxies(self):
  589. """
  590. Makes CreateModel statements for proxy models.
  591. We use the same statements as that way there's less code duplication,
  592. but of course for proxy models we can skip all that pointless field
  593. stuff and just chuck out an operation.
  594. """
  595. added = set(self.new_proxy_keys) - set(self.old_proxy_keys)
  596. for app_label, model_name in sorted(added):
  597. model_state = self.to_state.models[app_label, model_name]
  598. assert model_state.options.get("proxy")
  599. # Depend on the deletion of any possible non-proxy version of us
  600. dependencies = [
  601. (app_label, model_name, None, False),
  602. ]
  603. # Depend on all bases
  604. for base in model_state.bases:
  605. if isinstance(base, six.string_types) and "." in base:
  606. base_app_label, base_name = base.split(".", 1)
  607. dependencies.append((base_app_label, base_name, None, True))
  608. # Generate creation operation
  609. self.add_operation(
  610. app_label,
  611. operations.CreateModel(
  612. name=model_state.name,
  613. fields=[],
  614. options=model_state.options,
  615. bases=model_state.bases,
  616. managers=model_state.managers,
  617. ),
  618. # Depend on the deletion of any possible non-proxy version of us
  619. dependencies=dependencies,
  620. )
  621. def generate_deleted_models(self):
  622. """
  623. Find all deleted models (managed and unmanaged) and make delete
  624. operations for them as well as separate operations to delete any
  625. foreign key or M2M relationships (we'll optimize these back in later
  626. if we can).
  627. We also bring forward removal of any model options that refer to
  628. collections of fields - the inverse of generate_created_models().
  629. """
  630. new_keys = set(self.new_model_keys).union(self.new_unmanaged_keys)
  631. deleted_models = set(self.old_model_keys) - new_keys
  632. deleted_unmanaged_models = set(self.old_unmanaged_keys) - new_keys
  633. all_deleted_models = chain(sorted(deleted_models), sorted(deleted_unmanaged_models))
  634. for app_label, model_name in all_deleted_models:
  635. model_state = self.from_state.models[app_label, model_name]
  636. model = self.old_apps.get_model(app_label, model_name)
  637. if not model._meta.managed:
  638. # Skip here, no need to handle fields for unmanaged models
  639. continue
  640. # Gather related fields
  641. related_fields = {}
  642. for field in model._meta.local_fields:
  643. if field.remote_field:
  644. if field.remote_field.model:
  645. related_fields[field.name] = field
  646. # through will be none on M2Ms on swapped-out models;
  647. # we can treat lack of through as auto_created=True, though.
  648. if (getattr(field.remote_field, "through", None)
  649. and not field.remote_field.through._meta.auto_created):
  650. related_fields[field.name] = field
  651. for field in model._meta.local_many_to_many:
  652. if field.remote_field.model:
  653. related_fields[field.name] = field
  654. if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
  655. related_fields[field.name] = field
  656. # Generate option removal first
  657. unique_together = model_state.options.pop('unique_together', None)
  658. index_together = model_state.options.pop('index_together', None)
  659. if unique_together:
  660. self.add_operation(
  661. app_label,
  662. operations.AlterUniqueTogether(
  663. name=model_name,
  664. unique_together=None,
  665. )
  666. )
  667. if index_together:
  668. self.add_operation(
  669. app_label,
  670. operations.AlterIndexTogether(
  671. name=model_name,
  672. index_together=None,
  673. )
  674. )
  675. # Then remove each related field
  676. for name, field in sorted(related_fields.items()):
  677. self.add_operation(
  678. app_label,
  679. operations.RemoveField(
  680. model_name=model_name,
  681. name=name,
  682. )
  683. )
  684. # Finally, remove the model.
  685. # This depends on both the removal/alteration of all incoming fields
  686. # and the removal of all its own related fields, and if it's
  687. # a through model the field that references it.
  688. dependencies = []
  689. for related_object in model._meta.related_objects:
  690. related_object_app_label = related_object.related_model._meta.app_label
  691. object_name = related_object.related_model._meta.object_name
  692. field_name = related_object.field.name
  693. dependencies.append((related_object_app_label, object_name, field_name, False))
  694. if not related_object.many_to_many:
  695. dependencies.append((related_object_app_label, object_name, field_name, "alter"))
  696. for name, field in sorted(related_fields.items()):
  697. dependencies.append((app_label, model_name, name, False))
  698. # We're referenced in another field's through=
  699. through_user = self.through_users.get((app_label, model_state.name_lower))
  700. if through_user:
  701. dependencies.append((through_user[0], through_user[1], through_user[2], False))
  702. # Finally, make the operation, deduping any dependencies
  703. self.add_operation(
  704. app_label,
  705. operations.DeleteModel(
  706. name=model_state.name,
  707. ),
  708. dependencies=list(set(dependencies)),
  709. )
  710. def generate_deleted_proxies(self):
  711. """
  712. Makes DeleteModel statements for proxy models.
  713. """
  714. deleted = set(self.old_proxy_keys) - set(self.new_proxy_keys)
  715. for app_label, model_name in sorted(deleted):
  716. model_state = self.from_state.models[app_label, model_name]
  717. assert model_state.options.get("proxy")
  718. self.add_operation(
  719. app_label,
  720. operations.DeleteModel(
  721. name=model_state.name,
  722. ),
  723. )
  724. def generate_renamed_fields(self):
  725. """
  726. Works out renamed fields
  727. """
  728. self.renamed_fields = {}
  729. for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys):
  730. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  731. old_model_state = self.from_state.models[app_label, old_model_name]
  732. field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name)
  733. # Scan to see if this is actually a rename!
  734. field_dec = self.deep_deconstruct(field)
  735. for rem_app_label, rem_model_name, rem_field_name in sorted(self.old_field_keys - self.new_field_keys):
  736. if rem_app_label == app_label and rem_model_name == model_name:
  737. old_field_dec = self.deep_deconstruct(old_model_state.get_field_by_name(rem_field_name))
  738. if field.remote_field and field.remote_field.model and 'to' in old_field_dec[2]:
  739. old_rel_to = old_field_dec[2]['to']
  740. if old_rel_to in self.renamed_models_rel:
  741. old_field_dec[2]['to'] = self.renamed_models_rel[old_rel_to]
  742. if old_field_dec == field_dec:
  743. if self.questioner.ask_rename(model_name, rem_field_name, field_name, field):
  744. self.add_operation(
  745. app_label,
  746. operations.RenameField(
  747. model_name=model_name,
  748. old_name=rem_field_name,
  749. new_name=field_name,
  750. )
  751. )
  752. self.old_field_keys.remove((rem_app_label, rem_model_name, rem_field_name))
  753. self.old_field_keys.add((app_label, model_name, field_name))
  754. self.renamed_fields[app_label, model_name, field_name] = rem_field_name
  755. break
  756. def generate_added_fields(self):
  757. """
  758. Fields that have been added
  759. """
  760. for app_label, model_name, field_name in sorted(self.new_field_keys - self.old_field_keys):
  761. self._generate_added_field(app_label, model_name, field_name)
  762. def _generate_added_field(self, app_label, model_name, field_name):
  763. field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name)
  764. # Fields that are foreignkeys/m2ms depend on stuff
  765. dependencies = []
  766. if field.remote_field and field.remote_field.model:
  767. # Account for FKs to swappable models
  768. swappable_setting = getattr(field, 'swappable_setting', None)
  769. if swappable_setting is not None:
  770. dep_app_label = "__setting__"
  771. dep_object_name = swappable_setting
  772. else:
  773. dep_app_label = field.remote_field.model._meta.app_label
  774. dep_object_name = field.remote_field.model._meta.object_name
  775. dependencies = [(dep_app_label, dep_object_name, None, True)]
  776. if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
  777. dependencies.append((
  778. field.remote_field.through._meta.app_label,
  779. field.remote_field.through._meta.object_name,
  780. None,
  781. True,
  782. ))
  783. # You can't just add NOT NULL fields with no default or fields
  784. # which don't allow empty strings as default.
  785. preserve_default = True
  786. if (not field.null and not field.has_default() and
  787. not isinstance(field, models.ManyToManyField) and
  788. not (field.blank and field.empty_strings_allowed)):
  789. field = field.clone()
  790. field.default = self.questioner.ask_not_null_addition(field_name, model_name)
  791. preserve_default = False
  792. self.add_operation(
  793. app_label,
  794. operations.AddField(
  795. model_name=model_name,
  796. name=field_name,
  797. field=field,
  798. preserve_default=preserve_default,
  799. ),
  800. dependencies=dependencies,
  801. )
  802. def generate_removed_fields(self):
  803. """
  804. Fields that have been removed.
  805. """
  806. for app_label, model_name, field_name in sorted(self.old_field_keys - self.new_field_keys):
  807. self._generate_removed_field(app_label, model_name, field_name)
  808. def _generate_removed_field(self, app_label, model_name, field_name):
  809. self.add_operation(
  810. app_label,
  811. operations.RemoveField(
  812. model_name=model_name,
  813. name=field_name,
  814. ),
  815. # We might need to depend on the removal of an
  816. # order_with_respect_to or index/unique_together operation;
  817. # this is safely ignored if there isn't one
  818. dependencies=[
  819. (app_label, model_name, field_name, "order_wrt_unset"),
  820. (app_label, model_name, field_name, "foo_together_change"),
  821. ],
  822. )
  823. def generate_altered_fields(self):
  824. """
  825. Fields that have been altered.
  826. """
  827. for app_label, model_name, field_name in sorted(self.old_field_keys.intersection(self.new_field_keys)):
  828. # Did the field change?
  829. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  830. old_field_name = self.renamed_fields.get((app_label, model_name, field_name), field_name)
  831. old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field(old_field_name)
  832. new_field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name)
  833. # Implement any model renames on relations; these are handled by RenameModel
  834. # so we need to exclude them from the comparison
  835. if hasattr(new_field, "remote_field") and getattr(new_field.remote_field, "model", None):
  836. rename_key = (
  837. new_field.remote_field.model._meta.app_label,
  838. new_field.remote_field.model._meta.model_name,
  839. )
  840. if rename_key in self.renamed_models:
  841. new_field.remote_field.model = old_field.remote_field.model
  842. old_field_dec = self.deep_deconstruct(old_field)
  843. new_field_dec = self.deep_deconstruct(new_field)
  844. if old_field_dec != new_field_dec:
  845. both_m2m = (
  846. isinstance(old_field, models.ManyToManyField) and
  847. isinstance(new_field, models.ManyToManyField)
  848. )
  849. neither_m2m = (
  850. not isinstance(old_field, models.ManyToManyField) and
  851. not isinstance(new_field, models.ManyToManyField)
  852. )
  853. if both_m2m or neither_m2m:
  854. # Either both fields are m2m or neither is
  855. preserve_default = True
  856. if (old_field.null and not new_field.null and not new_field.has_default() and
  857. not isinstance(new_field, models.ManyToManyField)):
  858. field = new_field.clone()
  859. new_default = self.questioner.ask_not_null_alteration(field_name, model_name)
  860. if new_default is not models.NOT_PROVIDED:
  861. field.default = new_default
  862. preserve_default = False
  863. else:
  864. field = new_field
  865. self.add_operation(
  866. app_label,
  867. operations.AlterField(
  868. model_name=model_name,
  869. name=field_name,
  870. field=field,
  871. preserve_default=preserve_default,
  872. )
  873. )
  874. else:
  875. # We cannot alter between m2m and concrete fields
  876. self._generate_removed_field(app_label, model_name, field_name)
  877. self._generate_added_field(app_label, model_name, field_name)
  878. def _generate_altered_foo_together(self, operation):
  879. option_name = operation.option_name
  880. for app_label, model_name in sorted(self.kept_model_keys):
  881. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  882. old_model_state = self.from_state.models[app_label, old_model_name]
  883. new_model_state = self.to_state.models[app_label, model_name]
  884. # We run the old version through the field renames to account for those
  885. old_value = old_model_state.options.get(option_name) or set()
  886. if old_value:
  887. old_value = {
  888. tuple(
  889. self.renamed_fields.get((app_label, model_name, n), n)
  890. for n in unique
  891. )
  892. for unique in old_value
  893. }
  894. new_value = new_model_state.options.get(option_name) or set()
  895. if new_value:
  896. new_value = set(new_value)
  897. if old_value != new_value:
  898. self.add_operation(
  899. app_label,
  900. operation(
  901. name=model_name,
  902. **{option_name: new_value}
  903. )
  904. )
  905. def generate_altered_unique_together(self):
  906. self._generate_altered_foo_together(operations.AlterUniqueTogether)
  907. def generate_altered_index_together(self):
  908. self._generate_altered_foo_together(operations.AlterIndexTogether)
  909. def generate_altered_db_table(self):
  910. models_to_check = self.kept_model_keys.union(self.kept_proxy_keys).union(self.kept_unmanaged_keys)
  911. for app_label, model_name in sorted(models_to_check):
  912. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  913. old_model_state = self.from_state.models[app_label, old_model_name]
  914. new_model_state = self.to_state.models[app_label, model_name]
  915. old_db_table_name = old_model_state.options.get('db_table')
  916. new_db_table_name = new_model_state.options.get('db_table')
  917. if old_db_table_name != new_db_table_name:
  918. self.add_operation(
  919. app_label,
  920. operations.AlterModelTable(
  921. name=model_name,
  922. table=new_db_table_name,
  923. )
  924. )
  925. def generate_altered_options(self):
  926. """
  927. Works out if any non-schema-affecting options have changed and
  928. makes an operation to represent them in state changes (in case Python
  929. code in migrations needs them)
  930. """
  931. models_to_check = self.kept_model_keys.union(
  932. self.kept_proxy_keys
  933. ).union(
  934. self.kept_unmanaged_keys
  935. ).union(
  936. # unmanaged converted to managed
  937. set(self.old_unmanaged_keys).intersection(self.new_model_keys)
  938. ).union(
  939. # managed converted to unmanaged
  940. set(self.old_model_keys).intersection(self.new_unmanaged_keys)
  941. )
  942. for app_label, model_name in sorted(models_to_check):
  943. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  944. old_model_state = self.from_state.models[app_label, old_model_name]
  945. new_model_state = self.to_state.models[app_label, model_name]
  946. old_options = dict(
  947. option for option in old_model_state.options.items()
  948. if option[0] in AlterModelOptions.ALTER_OPTION_KEYS
  949. )
  950. new_options = dict(
  951. option for option in new_model_state.options.items()
  952. if option[0] in AlterModelOptions.ALTER_OPTION_KEYS
  953. )
  954. if old_options != new_options:
  955. self.add_operation(
  956. app_label,
  957. operations.AlterModelOptions(
  958. name=model_name,
  959. options=new_options,
  960. )
  961. )
  962. def generate_altered_order_with_respect_to(self):
  963. for app_label, model_name in sorted(self.kept_model_keys):
  964. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  965. old_model_state = self.from_state.models[app_label, old_model_name]
  966. new_model_state = self.to_state.models[app_label, model_name]
  967. if (old_model_state.options.get("order_with_respect_to") !=
  968. new_model_state.options.get("order_with_respect_to")):
  969. # Make sure it comes second if we're adding
  970. # (removal dependency is part of RemoveField)
  971. dependencies = []
  972. if new_model_state.options.get("order_with_respect_to"):
  973. dependencies.append((
  974. app_label,
  975. model_name,
  976. new_model_state.options["order_with_respect_to"],
  977. True,
  978. ))
  979. # Actually generate the operation
  980. self.add_operation(
  981. app_label,
  982. operations.AlterOrderWithRespectTo(
  983. name=model_name,
  984. order_with_respect_to=new_model_state.options.get('order_with_respect_to'),
  985. ),
  986. dependencies=dependencies,
  987. )
  988. def generate_altered_managers(self):
  989. for app_label, model_name in sorted(self.kept_model_keys):
  990. old_model_name = self.renamed_models.get((app_label, model_name), model_name)
  991. old_model_state = self.from_state.models[app_label, old_model_name]
  992. new_model_state = self.to_state.models[app_label, model_name]
  993. if old_model_state.managers != new_model_state.managers:
  994. self.add_operation(
  995. app_label,
  996. operations.AlterModelManagers(
  997. name=model_name,
  998. managers=new_model_state.managers,
  999. )
  1000. )
  1001. def arrange_for_graph(self, changes, graph, migration_name=None):
  1002. """
  1003. Takes in a result from changes() and a MigrationGraph,
  1004. and fixes the names and dependencies of the changes so they
  1005. extend the graph from the leaf nodes for each app.
  1006. """
  1007. leaves = graph.leaf_nodes()
  1008. name_map = {}
  1009. for app_label, migrations in list(changes.items()):
  1010. if not migrations:
  1011. continue
  1012. # Find the app label's current leaf node
  1013. app_leaf = None
  1014. for leaf in leaves:
  1015. if leaf[0] == app_label:
  1016. app_leaf = leaf
  1017. break
  1018. # Do they want an initial migration for this app?
  1019. if app_leaf is None and not self.questioner.ask_initial(app_label):
  1020. # They don't.
  1021. for migration in migrations:
  1022. name_map[(app_label, migration.name)] = (app_label, "__first__")
  1023. del changes[app_label]
  1024. continue
  1025. # Work out the next number in the sequence
  1026. if app_leaf is None:
  1027. next_number = 1
  1028. else:
  1029. next_number = (self.parse_number(app_leaf[1]) or 0) + 1
  1030. # Name each migration
  1031. for i, migration in enumerate(migrations):
  1032. if i == 0 and app_leaf:
  1033. migration.dependencies.append(app_leaf)
  1034. if i == 0 and not app_leaf:
  1035. new_name = "0001_%s" % migration_name if migration_name else "0001_initial"
  1036. else:
  1037. new_name = "%04i_%s" % (
  1038. next_number,
  1039. migration_name or self.suggest_name(migration.operations)[:100],
  1040. )
  1041. name_map[(app_label, migration.name)] = (app_label, new_name)
  1042. next_number += 1
  1043. migration.name = new_name
  1044. # Now fix dependencies
  1045. for app_label, migrations in changes.items():
  1046. for migration in migrations:
  1047. migration.dependencies = [name_map.get(d, d) for d in migration.dependencies]
  1048. return changes
  1049. def _trim_to_apps(self, changes, app_labels):
  1050. """
  1051. Takes changes from arrange_for_graph and set of app labels and
  1052. returns a modified set of changes which trims out as many migrations
  1053. that are not in app_labels as possible.
  1054. Note that some other migrations may still be present, as they may be
  1055. required dependencies.
  1056. """
  1057. # Gather other app dependencies in a first pass
  1058. app_dependencies = {}
  1059. for app_label, migrations in changes.items():
  1060. for migration in migrations:
  1061. for dep_app_label, name in migration.dependencies:
  1062. app_dependencies.setdefault(app_label, set()).add(dep_app_label)
  1063. required_apps = set(app_labels)
  1064. # Keep resolving till there's no change
  1065. old_required_apps = None
  1066. while old_required_apps != required_apps:
  1067. old_required_apps = set(required_apps)
  1068. for app_label in list(required_apps):
  1069. required_apps.update(app_dependencies.get(app_label, set()))
  1070. # Remove all migrations that aren't needed
  1071. for app_label in list(changes.keys()):
  1072. if app_label not in required_apps:
  1073. del changes[app_label]
  1074. return changes
  1075. @classmethod
  1076. def suggest_name(cls, ops):
  1077. """
  1078. Given a set of operations, suggests a name for the migration
  1079. they might represent. Names are not guaranteed to be unique,
  1080. but we put some effort in to the fallback name to avoid VCS conflicts
  1081. if we can.
  1082. """
  1083. if len(ops) == 1:
  1084. if isinstance(ops[0], operations.CreateModel):
  1085. return ops[0].name_lower
  1086. elif isinstance(ops[0], operations.DeleteModel):
  1087. return "delete_%s" % ops[0].name_lower
  1088. elif isinstance(ops[0], operations.AddField):
  1089. return "%s_%s" % (ops[0].model_name_lower, ops[0].name_lower)
  1090. elif isinstance(ops[0], operations.RemoveField):
  1091. return "remove_%s_%s" % (ops[0].model_name_lower, ops[0].name_lower)
  1092. elif len(ops) > 1:
  1093. if all(isinstance(o, operations.CreateModel) for o in ops):
  1094. return "_".join(sorted(o.name_lower for o in ops))
  1095. return "auto_%s" % datetime.datetime.now().strftime("%Y%m%d_%H%M")
  1096. @classmethod
  1097. def parse_number(cls, name):
  1098. """
  1099. Given a migration name, tries to extract a number from the
  1100. beginning of it. If no number found, returns None.
  1101. """
  1102. match = re.match(r'^\d+', name)
  1103. if match:
  1104. return int(match.group())
  1105. return None