I was reading this link in the official history 
<https://code.djangoproject.com/ticket/6095#comment:31> and this other link 
in this group 
<https://groups.google.com/forum/#!topic/django-developers/J-ycVFfgb4E>, 
but still do not understand why the issue against a way to call .add() to 
add a through model. I thought several approaches (they are all backward 
compatible for the end-user) that could work:

   1. Avoid the restriction to call add() if the model has only the two FK 
   fields.
   2. An additional way to call .add() specifying additional fields to fill 
   (this one is not mine; was discussed in the linked thread). You risk 
   getting a (wrapped?) exception if you do not populate other fields 
   appropriately.
   3. (This one was the first I thought and perhaps the easiest to 
   implement) Allow the ManyToManyField to specify a kwarg like 
   `through_factory=` which expects a callable which would populate more data. 
   The restriction to call .add() would remain if no `through_factory=` is 
   specified.
   4. Avoid the restriction to call delete() if the model has only the two 
   FK fields. 
   
I considered these cases:

   - It is quite trivial a model with only two fields, but perhaps the 
   intermediate models could have additional useful methods. I see no trouble 
   having such model and allowing .add() or .delete() calls there.
   - Having a special factory method would allow calls to .add() since we'd 
   be providing a way to make .add() actually know how to create an instance 
   of the intermediate model.
   - You can combine these points, implement one, none, or all of them.
   - (I did not consider extended use cases for delete() intentionally, 
   since perhaps a strange model (with different field pairs) could fit in 
   different relationships, although I cannot think in a case with multiple 
   relationships not incurrin in, perhaps, duplicate data when tried to be 
   used as through= model, but anyway I prefer to keep silence for other cases 
   involving delete(), but the case I stated).
   - It is up to the user to be careful regarding migrating an intermediate 
   model regarding adding, changing, or deleting fields. But anyway, this 
   applies to any modification in the database models right now.
   - Points 1, 2, 3 and/or 4 could be implemented with no clash. A combined 
   approach of 1, 2, 3 would look like this (this flow only applies for the 
   case when the through= is present - such scenario right now only consists 
   of raising an exception; the case with no through= model would not be 
   affected at all):
      - Instantiate `instance = ThroughModel(fka=a, fkb=b, 
      **kwargs_from_add)` with the respective model instances a and b, from 
      classes A and B which hold the desired M2M relationship. In this case, 
the 
      point 2 just adds the **kwargs_from_add. If point 2 is not implemented, 
no 
      **kwargs_from_add would be present.
      - (*If point 3 is implemented*) Call the callable in 
      `through_factory=` invoking it `like_this(instance)`, if the callable is 
      present. It is expected to save the instance.
      - (*If either point 1 is implemented and the model has only two 
      fields, or point 2 is implemented*) Manually save the instance (if 
      point 3 was not implemented or it was but the factory callable was not 
      specified). (*Otherwise - point 2 not implemented AND (point 1 not 
      implemented or model with more than two fields*)) Raise the currently 
      implemented exception for the .add() method with through= specified (with 
a 
      different string message) because the through_factory was not present, 
and 
      so the framework does not know how to populate additional fields.
      - Catch-and-reraise (or don't catch at all and let them be) the error 
      for missing data in the tried-to-save model.
   - An example of the callable in point 3 would be like this (just an 
   example for, say, a game!):
      - def on_added(through_model_instance):
          through_model_instance.balance = 1000.0 #although this one could 
      be a default value at db level.
          through_model_instance.save()
          through_model_instance.achievements.create(tag=
      'joined-this-relation')
      
I understand these approaches, combined or not, could not be perfect or 
bug-free. But I'd like to discuss them instead of plainly discard them. 
AFAIK right now the calls to .add() are disallowed when through is 
specified.

Could we work or at least discuss these use cases now? The history I quoted 
seems to be pretty.... historic, and we're in 2017. The first thing I'd 
like to know right not (with django 1.10 alive) is the feasability of this 
feature in a future django version.

I await your comments and/or criticism ^^.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/ec5ffdfc-ef4b-4c30-a53d-d427cbe053e2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to