Opened 6 years ago

Closed 2 years ago

#14549 closed New feature (fixed)

Disambiguation of target/source fields for intermediary models when using ManyToManyField

Reported by: Kronuz Owned by: dfunckt
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Kronuz, akiskesoglou@… Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


In cases where one has more than one foreign keys to either or both the source or the target models in a intermediary "through" model when using a ManyToManyField, django raises a validation error stating the ambiguity of the situation. To disambiguate this, I suggest adding two optional arguments to ManyToManyFields for those cases: 'source_fk_name' and 'target_fk_name'. I'm attaching a patch with an implementation of my suggestion.

Attachments (4)

#14549-intermediary_m2m_disambiguation.diff (6.0 KB) - added by Kronuz 6 years ago.
#14549-intermediary_m2m_disambiguation_fixed_tests.diff (9.7 KB) - added by Kronuz 5 years ago.
patch_commit_00e95a65d316.patch (4.3 KB) - added by dfunckt 3 years ago.
updated patch for django@9db4271bd11ac23a5a565 (5.6 KB) - added by dfunckt 3 years ago.
test project

Download all attachments as: .zip

Change History (19)

Changed 6 years ago by Kronuz

comment:1 Changed 6 years ago by ramiro

  • Needs documentation unset
  • Needs tests set
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

This needs tests and is currently causing a test error precisely in the model validation tests (modeltests.invalid_models):

FAIL: runTest (__main__.InvalidModelTestCase)
Traceback (most recent call last):
  File "./", line 85, in runTest
    self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
AssertionError: False is not True : Unexpected Errors: Intermediary model RelationshipDoubleFK has more than one foreign key to Person. Add a target_fk_name argument to the definition for tertiary.

comment:2 Changed 5 years ago by julien

  • Severity set to Normal
  • Type set to New feature

comment:3 Changed 5 years ago by Kronuz

  • Easy pickings unset
  • UI/UX unset

I have fixed the error in the tests (it was only an error due the new messages) and improved the patch a little, cleaning the messages a bit, fixing the wording and completing the help. It also now validates the case of many-to-many relationships to itself. Perhaps it needs a test where it actually uses the source_fk_name and target_fk_name arguments... but I'm not too sure on how to go about adding such test. I'm attaching the file now.

comment:4 Changed 5 years ago by Kronuz

  • Cc Kronuz added

comment:5 Changed 3 years ago by jacob

  • Triage Stage changed from Design decision needed to Accepted

comment:6 Changed 3 years ago by dfunckt

I'm attaching an updated patch that works on master and a test project with extra tests that prove it works. I haven't written any documentation.

All tests pass (i.e. both extras and Django's existing tests).

After loic84's suggestion in IRC, I implemented this feature as a through_fields=('<source_field_name>', '<target_field_name>') keyword argument.

I'd love to have feedback and see the feature eventually added to Django.

Changed 3 years ago by dfunckt

updated patch for django@9db4271bd11ac23a5a565

Changed 3 years ago by dfunckt

test project

comment:7 Changed 3 years ago by loic84

It's worth noting that I suggested through_fields=tuple() before knowing and reviewing the existing patch; before we move forward, we need to make a call on the public API.

Personally I like through_fields better, my rationale being:

  • The through_ prefix makes it obvious it's an option that is only available to custom through relations.
  • IMO what is "source" and "target" doesn't always make sense for M2M (i.e. anything other than symmetrical and relations to self). In that respect, I would document it as through_fields=('<field1>', '<field2>') and leave the concept of "source" and "target" out of the equation (with a special note for symmetrical=False).
  • I prefer being fully explicit, rather than having a fallback mechanism for only one of the FK.

@dfunckt, would you mind integrating your tests directly in the Django test suite (probably in django/tests/many_to_many/ rather than in a separate test project? Also it would be helpful if you made a github feature branch against Django's master (, that would facilitate the review process.

Edit: Reworded confusing point regarding "source" and "target".

Version 1, edited 3 years ago by loic84 (previous) (next) (diff)

comment:8 Changed 3 years ago by loic84

  • Cc loic@… added

comment:9 Changed 3 years ago by dfunckt

  • Cc akiskesoglou@… added
  • Needs tests unset

Added tests, documentation and cleaned up the code a bit. Just made a pull request:

comment:10 Changed 3 years ago by dfunckt

For this patch to go forward, is it possible that a core dev can confirm or discuss the API?

I personally agree with loic84 regarding the API which I believe is short, simple and explicit. However, I'm all for re-implementing the patch if the suggested API is not accepted and there are other suggestions.

comment:11 Changed 3 years ago by dfunckt

  • Owner changed from nobody to dfunckt
  • Status changed from new to assigned

comment:12 Changed 2 years ago by dfunckt

  • Triage Stage changed from Accepted to Ready for checkin

I'm marking as RTC as suggested by akaariai, after review.

comment:13 Changed 2 years ago by dfunckt

  • Triage Stage changed from Ready for checkin to Accepted

I'm removing the RFC flag, since we're currently trying to improve the docs a bit, along with loic84.

comment:14 Changed 2 years ago by loic84

  • Cc loic@… removed
  • Triage Stage changed from Accepted to Ready for checkin

Looks good to me, tested, flake8ed, has lots of docs and tests.

comment:15 Changed 2 years ago by Anssi Kääriäinen <akaariai@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In c627da0ccc12861163f28177aa7538b420a9d310:

Fixed #14549 - Removed restriction of single FKs on intermediary tables

Thanks to Loic Bistuer for review. Minor changes to error messages
done by committer.

Note: See TracTickets for help on using tickets.
Back to Top