#30966: Migration crashes due to foreign key issue, depending on otherwise
irrelevant order on MySQL.
-------------------------------------+-------------------------------------
Reporter: Peter Thomassen | Owner: Hasan
| Ramezani
Type: Bug | Status: assigned
Component: Migrations | Version: master
Severity: Normal | Resolution:
Keywords: migration mySQL | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Charette):
After doing a bit of investigation work for #31064 and revisiting #29000 I
think the solution proposed by Hasan makes the most sense for now and
here's why.
Let's take the setup defined to test #29000 as an example
{{{#!python
class Pony(models.Model):
name = models.CharField(max_length=20)
class Rider(models.Model):
pony = models.ForeignKey('test_rename_multiple.Pony', models.CASCADE)
class PonyRider(models.Model):
riders = models.ManyToManyField('Rider')
}}}
If a `RenameField('Pony', 'name', 'fancy_field)` operation is applied and
`Pony` is rendered from the new state only the `Rider.pony` pointer is
actually stale and needs to be repointed.
However we decided not to follow the repointing route because of all the
trouble it incurs. Instead we re-render only the direct relationships if
`delay=True` (only `Rider` in this case) or the full relationship tree if
`delay=False` (`Rider` and `PonyRider` in this case). A full relationship
tree re-rendering is slow hence why we try to use `delay=True` as much as
possible but when we do so references to direct relationships of the
reloaded models are left pointing at pre-re-rendering `Model` classes
which breaks `Options._populate_directed_relation_graph` mapping because
it currently relies on `Options` identity as key.
To reuse our example setup above, if `PonyRider -> Rider -> Pony` and we
`reload_model('app', 'pony', delay=True)` then `Pony` and `Rider` will be
reloaded as `Rider' -> Pony'` but `PonyRider` will still point at `Pony`
and not `Pony'` which makes any following operation relying on
`Pony'._meta.related_objects` break because `Pony'._meta is not
Pony._meta`.
If we look at how #29000 was addressed
[https://github.com/django/django/commit/fcc4e251dbc917118f73d7187ee2f4cbf3883f36
#diff-efb7d00c2383393046c9c5d842f45499R290 we can see that it works around
this issue by forcing a full relationship tree re-rendering as soon as any
model refers to a model on which a field is renamed]. This is really
wasteful but it gets the test passing in this particular case which is
more a bandaid than anything else. Fundamentally the `delay=True` model if
broken if it doesn't allow non-re-rendered models to maintain some
relationship with the re-rendered graph.
For these reasons and because model identity consistency is not necessary
beyond direct relationship by the current schema editor I think that
adjusting `Options._populate_directed_relation_graph` to use
`Options.label` as relationship key is our best way forward here as it
doesn't hurt non-`__fake__` model relationship resolution and it allows
`StateApps` to keep relying on the `delay=True` for model rendering until
schema alterations don't necessitate access to `ProjectState.apps`
anymore.
I'll submit a PR that reverts unnecessary `RenameField.state_forwards`
changes introduced by fcc4e251dbc917118f73d7187ee2f4cbf3883f36 and use
Hasan's `_populate_directed_relation_graph` adjustments to demonstrate
that the tests are passing. From that point, if everyone agrees that this
is the right way forward, I think we should keep this ticket opened as a
marker to add regression tests showing this is was properly addressed.
Thoughts on that approach Markus and Hasan?
--
Ticket URL: <https://code.djangoproject.com/ticket/30966#comment:21>
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/072.b34def39e4405d07706615cca19a12e9%40djangoproject.com.