#32263: squashmigrations produces incorrect result with a RenameModel on a ForeignKey target. -------------------------------------+------------------------------------- Reporter: InvalidInterrupt | Owner: Anvesh | Mishra Type: Bug | Status: assigned Component: Migrations | Version: 3.1 Severity: Normal | Resolution: Keywords: | Triage Stage: Accepted Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+-------------------------------------
Comment (by Durval Carvalho): I tried to deal with this problem as follows. In the CreateModel.reduce function, when executed with a RenameModel operation, I check if the CreateModel operation has any fields that may have been impacted by the RenameModel operation, because in this scenario, these fields need to be updated for this renamed model. {{{ def reduce(self, operation, app_label): ... elif impacted_fields := [ (_, field) for _, field in self.fields if field.remote_field and field.remote_field.model == f'{app_label}.{operation.old_name_lower}' ]: not_impacted_fields = [ (_, field) for (_, field) in self.fields if (_, field) not in impacted_fields ] fixed_fields = [] for (_, impacted_field) in impacted_fields: name, path, args, kwargs = impacted_field.deconstruct() kwargs['to'] = f'{app_label}.{operation.new_name_lower}' impacted_field = impacted_field.__class__(*args, **kwargs) fixed_fields.append((_, impacted_field)) return [ CreateModel( self.name, fields=not_impacted_fields + fixed_fields, bases=self.bases, managers=self.managers, ), ] ... }}} However, this approach did not work for the following reason. When the CreateModel operation is executed with its respective RenameModel, both are reduced to the new CreateModel operation. Then, some checks are made to decide whether this new resulting operation will be added to the list of new operations. But with this new reduction that I created, the other CreateModel operations, the ones that reference the renamed model, are also reduced, and this breaks the verification described below. {{{ ... for i, operation in enumerate(operations): right = True # Should we reduce on the right or on the left. # Compare it to each operation after it for j, other in enumerate(operations[i + 1 :]): result = operation.reduce(other, app_label) if isinstance(result, list): in_between = operations[i + 1 : i + j + 1] if right: new_operations.extend(in_between) new_operations.extend(result) elif all(op.reduce(other, app_label) is True for op in in_between): # <<<<<<< This condition fails (I didn't understand what is being checked here) # Perform a left reduction if all of the in- between # operations can optimize through other. new_operations.extend(result) new_operations.extend(in_between) else: # <<<<<<<< New operation `result` is not added to new operations list # Otherwise keep trying. new_operations.append(operation) break ... }}} Now I am stuck, trying to think of a way to work around this problem. Do any of you have any suggestions? -- Ticket URL: <https://code.djangoproject.com/ticket/32263#comment:14> 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/0107018715968041-0619c62c-bdda-4be2-9c9b-11f2fe328c16-000000%40eu-central-1.amazonses.com.