#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 [email protected].
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.