#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.