#30828: Add ManyToMany relationships in bulk
-------------------------------------+-------------------------------------
               Reporter:  David      |          Owner:  David Foster
  Foster                             |
                   Type:  New        |         Status:  assigned
  feature                            |
              Component:  Database   |        Version:  master
  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          |
-------------------------------------+-------------------------------------
 Given the following example model:

 {{{
 class M1(models.Model):
     m2_set = models.ManyToManyField('M2')
 }}}

 It is already possible to associate one M1 with many M2s with a single DB
 query:

 {{{
 m1.m2_set.add(*m2s)
 }}}

 However it's more difficult to associate many M1s with many M2s,
 particularly if you want to skip associations that already exist:

 {{{
 # NOTE: Does NOT skip associations that already exist!
 m1_and_m2_id_tuples = [(m1_id, m2_id), ...]
 M1_M2 = M1.m2_set.through
 M1_M2.objects.bulk_create([
     M1_M2(m1_id=m1_id, m2_id=m2_id)
     for (m1_id, m2_id) in
     m1_and_m2_id_tuples
 ])
 }}}

 I propose adding the following APIs to bulk-associate relationships:

 {{{
 M1.m2_set.add_pairs(*[(m1, m2), ...], assert_no_collisions=False)
 # --- OR ---
 M1.m2_set.add_pair_ids(*[(m1_id, m2_id), ...], assert_no_collisions=False)
 }}}

 I also propose to add the following paired APIs to bulk-disassociate
 relationships:

 {{{
 M1.m2_set.remove_pairs(*[(m1, m2), ...])
 # --- OR ---
 M1.m2_set.remove_pair_ids(*[(m1_id, m2_id), ...])
 }}}

 I have already written code for both of these cases and have been using it
 in production for a few years. It probably needs to be extended to support
 non-default database connections. Documentation+tests need to be added of
 course.

 Related thread on Django-developers:
 https://groups.google.com/forum/#!topic/django-developers/n8ZN5uuuM_Q

 API docstrings, with further details:

 {{{
 def add_pairs(
         self: ManyToManyDescriptor,  # M1.m2_set
         m1_m2_tuples: 'List[Tuple[M1, M2]]',
         *, assert_no_collisions: bool=False) -> None:
     """
     Creates many (M1, M2) associations with O(1) database queries.

     If any requested associations already exist, then they will be left
 alone.

     If you assert that none of the requested associations already exist,
     you can pass assert_no_collisions=True to save 1 database query.
     """

 def remove_pairs(
         self: ManyToManyDescriptor,  # M1.m2_set
         m1_m2_tuples: 'List[Tuple[M1, M2]]') -> None:
     """
     Deletes many (M1, M2) associations with O(1) database queries.
     """
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30828>
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 django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/052.0b591041163fc7808af54f98d7c850a9%40djangoproject.com.

Reply via email to