#26162: Data loss when ManyToManyField refers to the wrong table
-------------------------------------+-------------------------------------
Reporter: Ian-Foote | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by charettes):
* cc: charettes (added)
Comment:
I suspect this is caused by colliding `related_query_name`s.
When you ''hide'' a related manager by setting `related_name` to a value
ending with `'+'` the `related_query_name` is still set to its default
value (based on the model name).
If we explicit the model definitions created by Django here's what we
have:
{{{#!python
class Bar(models.Model):
class Meta:
app_label = 'app1'
class Foo(models.Model):
bars = models.ManyToManyField(Bar, related_name='+',
through='app1.FooBar')
class Meta:
app_label = 'app1'
class FooBar(models.Model):
bar = models.ForeignKey(
Bar, related_name='+', related_query_name='foobar'
)
foo = models.ForeignKey(
'app1.Foo', related_name='+', related_query_name='foobar'
)
class Meta:
app_label = 'app1'
class Foo(models.Model):
bars = models.ManyToManyField(Bar, related_name='+',
through='app2.FooBar')
class Meta:
app_label = 'app2'
class FooBar(models.Model):
bar = models.ForeignKey(
Bar, related_name='+', related_query_name='foobar'
)
foo = models.ForeignKey(
'app2.Foo', related_name='+', related_query_name='foobar'
)
class Meta:
app_label = 'app2'
}}}
As you can see there's a `related_query_name='foobar'` conflict on `Bar`
that makes `foo.bars.all()` (resolving to
`Bar.object.filter(foobar__foo=foo`) ambiguous. This clash is not detected
by the check framework because the
[https://github.com/django/django/blob/11fae7c9e4a30d88a4062eb3ee5e9fdfbcd7ba3e/django/db/models/fields/related.py#L197-L201
relationships are hidden].
In order to fix this I suggest we start by fixing the clash checks to run
even if the relationship is hidden, we just have to skip `E302` and `E304`
in this case.
Then we should consider making implicit intermediary model creation more
smart about this possible conflict by namespacing `related_query_name` by
application label. This is a backward incompatible change in some way
since users might have relied on the automatically generated queryname
even if unlikely. The backward incompatibility could be lessened by only
namespacing the queryname if the referenced model is from a different
application.
--
Ticket URL: <https://code.djangoproject.com/ticket/26162#comment:2>
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 post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/067.846b904f98c581a27717078b43d87f4d%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.