| 158 | | # Prepare field lists, and prepare a list of the fields that used |
| 159 | | # through models in the old state so we can make dependencies |
| 160 | | # from the through model deletion to the field that uses it. |
| 161 | | self.kept_model_keys = set(self.old_model_keys).intersection(self.new_model_keys) |
| 162 | | self.kept_proxy_keys = set(self.old_proxy_keys).intersection(self.new_proxy_keys) |
| 163 | | self.kept_unmanaged_keys = set(self.old_unmanaged_keys).intersection(self.new_unmanaged_keys) |
| 164 | | self.through_users = {} |
| 165 | | self.old_field_keys = set() |
| 166 | | self.new_field_keys = set() |
| 167 | | for app_label, model_name in sorted(self.kept_model_keys): |
| 168 | | old_model_name = self.renamed_models.get((app_label, model_name), model_name) |
| 169 | | old_model_state = self.from_state.models[app_label, old_model_name] |
| 170 | | new_model_state = self.to_state.models[app_label, model_name] |
| 171 | | self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields) |
| 172 | | self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields) |
| 173 | | |
| 174 | | # Through model map generation |
| 175 | | for app_label, model_name in sorted(self.old_model_keys): |
| 176 | | old_model_name = self.renamed_models.get((app_label, model_name), model_name) |
| 177 | | old_model_state = self.from_state.models[app_label, old_model_name] |
| 178 | | for field_name, field in old_model_state.fields: |
| 179 | | old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field(field_name) |
| 180 | | if (hasattr(old_field, "remote_field") and getattr(old_field.remote_field, "through", None) |
| 181 | | and not old_field.remote_field.through._meta.auto_created): |
| 182 | | through_key = ( |
| 183 | | old_field.remote_field.through._meta.app_label, |
| 184 | | old_field.remote_field.through._meta.model_name, |
| 185 | | ) |
| 186 | | self.through_users[through_key] = (app_label, old_model_name, field_name) |
| | 158 | # Prepare lists of fields and generate through model map |
| | 159 | self._prepare_field_lists() |
| | 160 | self._generate_through_model_map() |
| 223 | | # Now, we need to chop the lists of operations up into migrations with |
| 224 | | # dependencies on each other. |
| 225 | | # We do this by stepping up an app's list of operations until we |
| 226 | | # find one that has an outgoing dependency that isn't in another app's |
| 227 | | # migration yet (hasn't been chopped off its list). We then chop off the |
| 228 | | # operations before it into a migration and move onto the next app. |
| 229 | | # If we loop back around without doing anything, there's a circular |
| 230 | | # dependency (which _should_ be impossible as the operations are all |
| 231 | | # split at this point so they can't depend and be depended on) |
| | 196 | self._build_migration_list(graph) |
| | 197 | |
| | 198 | # OK, add in internal dependencies among the migrations |
| | 199 | for app_label, migrations in self.migrations.items(): |
| | 200 | for m1, m2 in zip(migrations, migrations[1:]): |
| | 201 | m2.dependencies.append((app_label, m1.name)) |
| | 202 | |
| | 203 | # De-dupe dependencies |
| | 204 | for app_label, migrations in self.migrations.items(): |
| | 205 | for migration in migrations: |
| | 206 | migration.dependencies = list(set(migration.dependencies)) |
| | 207 | |
| | 208 | # Optimize migrations |
| | 209 | for app_label, migrations in self.migrations.items(): |
| | 210 | for migration in migrations: |
| | 211 | migration.operations = MigrationOptimizer().optimize(migration.operations, app_label=app_label) |
| | 212 | |
| | 213 | return self.migrations |
| | 214 | |
| | 215 | def _prepare_field_lists(self): |
| | 216 | """ |
| | 217 | Prepare field lists, and prepare a list of the fields that used |
| | 218 | through models in the old state so we can make dependencies |
| | 219 | from the through model deletion to the field that uses it. |
| | 220 | """ |
| | 221 | |
| | 222 | self.kept_model_keys = set(self.old_model_keys).intersection(self.new_model_keys) |
| | 223 | self.kept_proxy_keys = set(self.old_proxy_keys).intersection(self.new_proxy_keys) |
| | 224 | self.kept_unmanaged_keys = set(self.old_unmanaged_keys).intersection(self.new_unmanaged_keys) |
| | 225 | self.through_users = {} |
| | 226 | self.old_field_keys = set() |
| | 227 | self.new_field_keys = set() |
| | 228 | for app_label, model_name in sorted(self.kept_model_keys): |
| | 229 | old_model_name = self.renamed_models.get((app_label, model_name), model_name) |
| | 230 | old_model_state = self.from_state.models[app_label, old_model_name] |
| | 231 | new_model_state = self.to_state.models[app_label, model_name] |
| | 232 | self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields) |
| | 233 | self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields) |
| | 234 | |
| | 235 | def _generate_through_model_map(self): |
| | 236 | """ |
| | 237 | Through model map generation |
| | 238 | """ |
| | 239 | |
| | 240 | for app_label, model_name in sorted(self.old_model_keys): |
| | 241 | old_model_name = self.renamed_models.get((app_label, model_name), model_name) |
| | 242 | old_model_state = self.from_state.models[app_label, old_model_name] |
| | 243 | for field_name, field in old_model_state.fields: |
| | 244 | old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field(field_name) |
| | 245 | if (hasattr(old_field, "remote_field") and getattr(old_field.remote_field, "through", None) |
| | 246 | and not old_field.remote_field.through._meta.auto_created): |
| | 247 | through_key = ( |
| | 248 | old_field.remote_field.through._meta.app_label, |
| | 249 | old_field.remote_field.through._meta.model_name, |
| | 250 | ) |
| | 251 | self.through_users[through_key] = (app_label, old_model_name, field_name) |
| | 252 | |
| | 253 | def _build_migration_list(self, graph=None): |
| | 254 | """ |
| | 255 | We need to chop the lists of operations up into migrations with |
| | 256 | dependencies on each other. We do this by stepping up an app's list of |
| | 257 | operations until we find one that has an outgoing dependency that isn't |
| | 258 | in another app's migration yet (hasn't been chopped off its list). We |
| | 259 | then chop off the operations before it into a migration and move onto |
| | 260 | the next app. If we loop back around without doing anything, there's a |
| | 261 | circular dependency (which _should_ be impossible as the operations are |
| | 262 | all split at this point so they can't depend and be depended on). |
| | 263 | """ |