Opened 6 years ago

Closed 3 years ago

#14549 closed New feature (fixed)

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

Reported by: German M. Bravo Owned by: Akis Kesoglou
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: German M. Bravo, 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

Description

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 German M. Bravo 6 years ago.
#14549-intermediary_m2m_disambiguation_fixed_tests.diff (9.7 KB) - added by German M. Bravo 5 years ago.
patch_commit_00e95a65d316.patch (4.3 KB) - added by Akis Kesoglou 3 years ago.
updated patch for django@9db4271bd11ac23a5a565
testm2mthrough.zip (5.6 KB) - added by Akis Kesoglou 3 years ago.
test project

Download all attachments as: .zip

Change History (19)

Changed 6 years ago by German M. Bravo

comment:1 Changed 6 years ago by Ramiro Morales

Needs tests: set
Triage Stage: UnreviewedDesign 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 "./runtests.py", line 85, in runTest
    self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
AssertionError: False is not True : Unexpected Errors: invalid_models.group: 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 6 years ago by Julien Phalip

Severity: Normal
Type: New feature

comment:3 Changed 5 years ago by German M. Bravo

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 German M. Bravo

Cc: German M. Bravo added

Changed 5 years ago by German M. Bravo

comment:5 Changed 4 years ago by Jacob

Triage Stage: Design decision neededAccepted

comment:6 Changed 3 years ago by Akis Kesoglou

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 Akis Kesoglou

updated patch for django@9db4271bd11ac23a5a565

Changed 3 years ago by Akis Kesoglou

Attachment: testm2mthrough.zip added

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 relations to self with symmetrical=False). 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/tests.py) rather than in a separate test project? Also it would be helpful if you made a github feature branch against Django's master (https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/working-with-git/), that would facilitate the review process.

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

Last edited 3 years ago by loic84 (previous) (diff)

comment:8 Changed 3 years ago by loic84

Cc: loic@… added

comment:9 Changed 3 years ago by Akis Kesoglou

Cc: akiskesoglou@… added
Needs tests: unset

Added tests, documentation and cleaned up the code a bit. Just made a pull request: https://github.com/django/django/pull/2327

comment:10 Changed 3 years ago by Akis Kesoglou

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 Akis Kesoglou

Owner: changed from nobody to Akis Kesoglou
Status: newassigned

comment:12 Changed 3 years ago by Akis Kesoglou

Triage Stage: AcceptedReady for checkin

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

comment:13 Changed 3 years ago by Akis Kesoglou

Triage Stage: Ready for checkinAccepted

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

comment:14 Changed 3 years ago by loic84

Cc: loic@… removed
Triage Stage: AcceptedReady for checkin

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

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

Resolution: fixed
Status: assignedclosed

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