#31788: Models migration with change field foreign to many and deleting unique together. ----------------------------+----------------------------------------- Reporter: budzichd | Owner: David Wobrock Type: Bug | Status: assigned Component: Migrations | Version: 3.0 Severity: Normal | Resolution: Keywords: | Triage Stage: Accepted Has patch: 1 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 ----------------------------+----------------------------------------- Changes (by David Wobrock):
* cc: David Wobrock (added) * owner: nobody => David Wobrock * has_patch: 0 => 1 * status: new => assigned Comment: Quite a funny bug actually in the autodetector and how we sort migration with respect to their dependencies. I can't exactly reproduce the described output, but something similar. Here is a little dive into the issue. When changing a field from FK to M2M, the autodetector goes within `django.db.migrations.autodetector.MigrationAutodetector.generate_altered_fields` and creates a `RemoveField`+`AddField`, which is fine and works. But we also generate a `AlterUniqueTogether`... Since we call `generate_removed_altered_unique_together` before `generate_altered_fields`, one would expect it to work as expected. And at first, we have the right operation order: `[AlterUniqueTogether, RemoveField, AddField]`. However, when sorting the operations with respect to their dependencies, we trigger the dependency that `RemoveField` should be after `AlterUniqueTogether`. Even if this condition is already satisfied, the `stable_topological_sort` changes the order and returns `[AlterUniqueTogether, AddField, RemoveField]`. The dependency is still satisfied, but our Remove/Add became an Add/Remove, which cannot work. In `tests/utils_tests/test_topological_sort.py` {{{ def test_preserve_satisfied_order(self): dependency_graph = {1: set(), 2: {1}, 3: set()} self.assertEqual( stable_topological_sort([1, 2, 3], dependency_graph), [1, 2, 3], ) }}} return {{{ ====================================================================== FAIL: test_preserve_satisfied_order (utils_tests.test_topological_sort.TopologicalSortTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/david/django/tests/utils_tests/test_topological_sort.py", line 29, in test_preserve_satisfied_order self.assertEqual( AssertionError: Lists differ: [1, 3, 2] != [1, 2, 3] First differing element 1: 3 2 - [1, 3, 2] + [1, 2, 3] }}} on my env (and since we rely on sets, I suspect that's why I don't have the same result as described in the ticket. I think that's why Simon is seeing a `[AddField, AlterUniqueTogether, RemoveField]`, which also satisfies the dependencies). (on top of that, the autodetector then optimizes the operations, and the `AddField` followed by `RemoveField` cancel each other out, and we end up with a single `[AlterUniqueTogether]`). Two possible approaches to fix this: 1. Making the `AddField` depend on `RemoveField`, so that we force their order 2. Changing the topological sort, so that it preserves the input order as much as possible Since the second might imply a large set of changes, so I tried implementing the first one in this [https://github.com/django/django/pull/15738 PR]. -- Ticket URL: <https://code.djangoproject.com/ticket/31788#comment:5> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/0107018105b881e1-04663909-0f5e-46fa-b13b-10cbc5d7779c-000000%40eu-central-1.amazonses.com.