From c3a23aa02faa1cf1d32e43d66858e793cd9ecac4 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Mon, 17 Feb 2025 13:45:31 -0500 Subject: [PATCH] Fixed #36197 -- Fixed improper many-to-many count() and exists() for non-pk to_field. Regression in 66e47ac69a7e71cf32eee312d05668d8f1ba24bb. Thanks mfontana-elem for the report and Sarah for the tests. --- django/db/models/fields/related_descriptors.py | 2 +- docs/releases/5.1.7.txt | 5 +++++ tests/m2m_through/tests.py | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index d461580acf..77ebe798b4 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -1172,7 +1172,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse): return None hints = {"instance": self.instance} manager = self.through._base_manager.db_manager(db, hints=hints) - filters = {self.source_field_name: self.instance.pk} + filters = {self.source_field_name: self.related_val[0]} # Nullable target rows must be excluded as well as they would have # been filtered out from an INNER JOIN. if self.target_field.null: diff --git a/docs/releases/5.1.7.txt b/docs/releases/5.1.7.txt index deda4f2f92..c32f8f5ae1 100644 --- a/docs/releases/5.1.7.txt +++ b/docs/releases/5.1.7.txt @@ -16,3 +16,8 @@ Bugfixes * Fixed a bug in Django 5.1 where ``FileSystemStorage``, with ``allow_overwrite`` set to ``True``, did not truncate the overwritten file content (:ticket:`36191`). + +* Fixed a regression in Django 5.1 where the ``count`` and ``exists`` methods + of ``ManyToManyField`` related managers would always return ``0`` and + ``False`` when the intermediary model back references used ``to_field`` + (:ticket:`36197`). diff --git a/tests/m2m_through/tests.py b/tests/m2m_through/tests.py index 83449a7c7b..81a47a2083 100644 --- a/tests/m2m_through/tests.py +++ b/tests/m2m_through/tests.py @@ -533,3 +533,11 @@ class M2mThroughToFieldsTests(TestCase): [choice[0] for choice in field.get_choices(include_blank=False)], ["pea", "potato", "tomato"], ) + + def test_count(self): + self.assertEqual(self.curry.ingredients.count(), 3) + self.assertEqual(self.tomato.recipes.count(), 1) + + def test_exists(self): + self.assertTrue(self.curry.ingredients.exists()) + self.assertTrue(self.tomato.recipes.exists())