Skip to content

Commit

Permalink
[2.2.x] Fixed #30828 -- Added how to remove/insert many-to-many relat…
Browse files Browse the repository at this point in the history
…ions in bulk to the database optimization docs.

Backport of 6a04e69 from master
  • Loading branch information
davidfstr authored and felixxm committed Nov 12, 2019
1 parent 612c2d1 commit afde973
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ answer newbie questions, and generally made Django that much better:
David Cramer <dcramer@gmail.com>
David Danier <david.danier@team23.de>
David Eklund
David Foster <david@dafoster.net>
David Gouldin <dgouldin@gmail.com>
david@kazserve.org
David Krauth
Expand Down
62 changes: 62 additions & 0 deletions docs/topics/db/optimization.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
<django.db.models.query.QuerySet.bulk_create>`, so make sure it's appropriate
for your use case.

Remove in bulk
--------------

When removing objects from :class:`ManyToManyFields
<django.db.models.ManyToManyField>`, 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
<django.db.models.ManyToManyField>`, 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.

0 comments on commit afde973

Please sign in to comment.