#26352: models.E003 check incorrectly prevents duplicate ManyToMany through-self
that differ by through_fields
-------------------------------------+-------------------------------------
Reporter: simonw | Owner: nobody
Type: Bug | Status: new
Component: Database | Version: 1.9
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Let's say we're building a Twitter-style friendship model, where a user
can follow other users, and can have users that follow them.
A sensible way to model that might look like this:
{{{#!python
class User(models.Model):
friends = models.ManyToManyField(
'self', through='Followship', symmetrical=False,
through_fields=('user', 'target'), related_name='+'
)
followers = models.ManyToManyField(
'self', through='Followship', symmetrical=False,
through_fields=('target', 'user'), related_name='+'
)
class Followship(models.Model):
user = models.ForeignKey(User, models.CASCADE, related_name='+')
target = models.ForeignKey(User, models.CASCADE, related_name='+')
}}}
Here we have an intermediary table called "Followship", which relates a
user to the target user that they are following.
We also have two helpful convenience ManyToMany fields defined on the
user: `user.friends.all()` returns all other users that the user is
following, while `user.followers.all()` returns the users that are
following our current user.
The above models should work fine... but they don't, because Django's
model checking framework throws the following error:
users.User: (models.E003) The model has two many-to-many relations
through the intermediate model 'users.Followship'.
I don't think this warning is warranted in this case, because the
`through_fields` arguments provided to the friends/followers
ManyToManyFields mean that the relationships defined here make sense and
the models should work correctly.
I've tested this theory by disabling the warning entirely using an over-
ride class method on user, like this:
{{{#!python
class User(models.Model):
friends = models.ManyToManyField(
'self', through='Followship', symmetrical=False,
through_fields=('user', 'target'), related_name='+'
)
followers = models.ManyToManyField(
'self', through='Followship', symmetrical=False,
through_fields=('target', 'user'), related_name='+'
)
@classmethod
def _check_m2m_through_same_relationship(cls):
# Disable models.E003 check for this model
return []
}}}
This does the trick: the check is suppressed, and the models work as
expected.
I think the model check framework is being overly strict here. I think it
should be modified to enable this pattern, provided the through_fields=
parameters on the duplicate ManyToMany fields are present and
differentiate the fields correctly.
--
Ticket URL: <https://code.djangoproject.com/ticket/26352>
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/049.af60830ff4c5fbb47f3d66ae1c30ef18%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.