﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
23733	Following #23556: manage multi-apps dependencies when squashing	"Stephane ""Twidi"" Angel"	nobody	"Following ticket #23556 and PR #3280, I found a problem with squashing on different apps, each one depending on the other at different step

`app1`:
  - `1_auto`
  - `2_auto`
  - `3_auto`, with dependency on `('app2', '2_auto')`
  - `4_auto`

With this squash:

  - `2_squashed_3` (squash of `2_auto` and `3_auto`)


And `app2`:

  - `1_auto`, with dependency on `('app1', '1_auto')`
  - `2_auto`

With this squash:

  - `1_squashed_2` (squash of `1_auto` and `2_auto`)


With this configuration, there is an error in `build_graph`:

{{{
#!python
File ""django/db/migrations/loader.py"", line 224, in build_graph
    normal[child_key].dependencies.remove(replaced)
KeyError: ('app1', '3_auto')
}}}


The reason is simple, `('app1', '3_auto')` where replaced by `('app1', '2_squashed_3')`

So I came up with this patch:

{{{
#!diff
diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py
index 9f8be33..0ee3794 100644
--- a/django/db/migrations/loader.py
+++ b/django/db/migrations/loader.py
@@ -219,8 +219,15 @@ class MigrationLoader(object):
                 for child_key in reverse_dependencies.get(replaced, set()):
                     if child_key in migration.replaces:
                         continue
-                    normal[child_key].dependencies.remove(replaced)
-                    normal[child_key].dependencies.append(key)
+                    # child_key may appear in a replacement
+                    if child_key in reverse_replacements:
+                        for replaced_child_key in reverse_replacements[child_key]:
+                            if replaced in replacing[replaced_child_key].dependencies:
+                                replacing[replaced_child_key].dependencies.remove(replaced)
+                                replacing[replaced_child_key].dependencies.append(key)
+                    else:
+                        normal[child_key].dependencies.remove(replaced)
+                        normal[child_key].dependencies.append(key)
             normal[key] = migration
             # Mark the replacement as applied if all its replaced ones are
             if all(applied_statuses):
}}}

Note that I loop on reverse_replacements[child_key], but I'm not sure how we can have many entries here

I'll provide a PR with two commits:

- one with a test showing the failure
- one with the patch"	Bug	new	Migrations	dev	Normal				Unreviewed	1	0	0	0	0	0
