@@ -655,6 +655,8 @@ contained in a single :meth:`~django.db.models.query.QuerySet.filter` call.
655655 ... )
656656 <QuerySet [<Blog: Beatles Blog>, <Blog: Beatles Blog>, <Blog: Pop Music Blog]>
657657
658+ .. _exclude-implementation:
659+
658660.. note::
659661
660662 The behavior of :meth:`~django.db.models.query.QuerySet.filter` for queries
@@ -1966,6 +1968,71 @@ relationships accept primary key values. For example, if ``e1`` and ``e2`` are
19661968 a.entry_set.set([e1, e2])
19671969 a.entry_set.set([e1.pk, e2.pk])
19681970
1971+ Filtering on many-to-many relationships
1972+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1973+
1974+ When calling ``filter()`` on a many-to-many relationship, be aware that the
1975+ join between ``Entry`` and the intermediary model to ``Author`` is performed
1976+ only once, resulting in a restrictive, or "sticky", filter. Consider the
1977+ following example:
1978+
1979+ .. code-block:: pycon
1980+
1981+ >>> from datetime import date
1982+ >>> batucada = Blog.objects.create(name="Batucada Blog")
1983+ >>> e = Entry.objects.create(
1984+ ... blog=batucada,
1985+ ... headline="Supporting social movements with drums",
1986+ ... pub_date=date(2019, 6, 14),
1987+ ... )
1988+
1989+ >>> gloria = Author.objects.create(name="Gloria")
1990+ >>> anna = Author.objects.create(name="Anna")
1991+ >>> e.authors.add(gloria, anna)
1992+
1993+ >>> anna.entry_set.filter(authors__name="Gloria")
1994+ <QuerySet []>
1995+
1996+ This filtered query is looking for blog entries that are co-authored by
1997+ ``anna`` and ``gloria``. You would expect it to return the entry ``e``.
1998+ However, the filter condition, which traverses the many-to-many
1999+ relationship between ``Entry`` and ``Author``, yields an empty
2000+ ``QuerySet``.
2001+
2002+ Since the join between ``Entry`` and the intermediary model to ``Author``
2003+ happens only once, no single object of the joined models - i.e., a relation
2004+ between one author and one entry - can fulfill the query condition (entries
2005+ that are co-authored by ``anna`` and ``gloria``). You can circumvent this
2006+ behavior by chaining two consecutive ``filter()`` calls, resulting in two
2007+ separate joins and thus a more permissive filter:
2008+
2009+ .. code-block:: pycon
2010+
2011+ >>> anna.entry_set.filter().filter(authors__name="Gloria")
2012+ <QuerySet [<Entry: Supporting social movements with drums>]>
2013+
2014+ .. admonition:: exclude() is also sticky
2015+
2016+ Please note that for this example,
2017+ :meth:`~django.db.models.query.QuerySet.exclude` behaves similarly
2018+ to :meth:`~django.db.models.query.QuerySet.filter` despite being
2019+ implemented differently. When traversing the many-to-many relationship,
2020+ it does not exclude the entry ``e`` despite being co-authored by Gloria:
2021+
2022+ >>> anna.entry_set.exclude(authors__name="Gloria")
2023+ <QuerySet [<Entry: Supporting social movements with drums>]>
2024+
2025+ When chaining a second ``exclude()`` call, an empty ``QuerySet`` is
2026+ returned, as expected:
2027+
2028+ >>> anna.entry_set.exclude().exclude(authors__name="Gloria")
2029+ <QuerySet []>
2030+
2031+ However, in other cases, :meth:`~django.db.models.query.QuerySet.exclude`
2032+ behaves differently from :meth:`~django.db.models.query.QuerySet.filter`.
2033+ See the :ref:`note <exclude-implementation>` in the "Spanning multi-valued
2034+ relationships" section above.
2035+
19692036One-to-one relationships
19702037------------------------
19712038
0 commit comments