From c598ffd2e18e05ae5853cbea3bc7e525180cbf45 Mon Sep 17 00:00:00 2001 From: David Foster Date: Sun, 20 Oct 2019 11:47:38 -0700 Subject: [PATCH] [3.0.x] Fixed #30828 -- Added how to remove/insert many-to-many relations in bulk to the database optimization docs. Backport of 6a04e69e686cf417b469d7676f93c2e3a9c8d6a3 from master --- AUTHORS | 1 + docs/topics/db/optimization.txt | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/AUTHORS b/AUTHORS index ee2ddc48cb1..642cdc0b613 100644 --- a/AUTHORS +++ b/AUTHORS @@ -230,6 +230,7 @@ answer newbie questions, and generally made Django that much better: David Cramer David Danier David Eklund + David Foster David Gouldin david@kazserve.org David Krauth diff --git a/docs/topics/db/optimization.txt b/docs/topics/db/optimization.txt index 01c17571ab8..d56a55960d3 100644 --- a/docs/topics/db/optimization.txt +++ b/docs/topics/db/optimization.txt @@ -412,3 +412,65 @@ objects to reduce the number of SQL queries. For example:: my_band.members.add(my_friend) ...where ``Bands`` and ``Artists`` have a many-to-many relationship. + +When inserting different pairs of objects into +:class:`~django.db.models.ManyToManyField` or when the custom +:attr:`~django.db.models.ManyToManyField.through` table is defined, use +:meth:`~django.db.models.query.QuerySet.bulk_create()` method to reduce the +number of SQL queries. For example:: + + PizzaToppingRelationship = Pizza.toppings.through + PizzaToppingRelationship.objects.bulk_create([ + PizzaToppingRelationship(pizza=my_pizza, topping=pepperoni), + PizzaToppingRelationship(pizza=your_pizza, topping=pepperoni), + PizzaToppingRelationship(pizza=your_pizza, topping=mushroom), + ], ignore_conflicts=True) + +...is preferable to:: + + my_pizza.toppings.add(pepperoni) + your_pizza.toppings.add(pepperoni, mushroom) + +...where ``Pizza`` and ``Topping`` have a many-to-many relationship. Note that +there are a number of :meth:`caveats to this method +`, so make sure it's appropriate +for your use case. + +Remove in bulk +-------------- + +When removing objects from :class:`ManyToManyFields +`, use +:meth:`~django.db.models.fields.related.RelatedManager.remove` with multiple +objects to reduce the number of SQL queries. For example:: + + my_band.members.remove(me, my_friend) + +...is preferable to:: + + my_band.members.remove(me) + my_band.members.remove(my_friend) + +...where ``Bands`` and ``Artists`` have a many-to-many relationship. + +When removing different pairs of objects from :class:`ManyToManyFields +`, use +:meth:`~django.db.models.query.QuerySet.delete` on a +:class:`~django.db.models.Q` expression with multiple +:attr:`~django.db.models.ManyToManyField.through` model instances to reduce +the number of SQL queries. For example:: + + from django.db.models import Q + PizzaToppingRelationship = Pizza.toppings.through + PizzaToppingRelationship.objects.filter( + Q(pizza=my_pizza, topping=pepperoni) | + Q(pizza=your_pizza, topping=pepperoni) | + Q(pizza=your_pizza, topping=mushroom) + ).delete() + +...is preferable to:: + + my_pizza.toppings.remove(pepperoni) + your_pizza.toppings.remove(pepperoni, mushroom) + +...where ``Pizza`` and ``Topping`` have a many-to-many relationship.