diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index 8468a0b01fa..ec603bc8afd 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -1064,7 +1064,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse): (self.model._meta.object_name, obj) ) else: - target_ids.add(obj) + target_ids.add(target_field.get_prep_value(obj)) return target_ids def _get_missing_target_ids(self, source_field_name, target_field_name, db, target_ids): diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py index a60ea424309..79d0fa420c2 100644 --- a/tests/many_to_many/tests.py +++ b/tests/many_to_many/tests.py @@ -1,7 +1,7 @@ from unittest import mock from django.db import transaction -from django.test import TestCase, skipUnlessDBFeature +from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from .models import ( Article, InheritedArticleA, InheritedArticleB, Publication, User, @@ -158,6 +158,14 @@ class ManyToManyTests(TestCase): with self.assertNumQueries(1): self.a1.publications.add(self.p1, self.p2) + @skipIfDBFeature('supports_ignore_conflicts') + def test_add_existing_different_type(self): + # A single SELECT query is necessary to compare existing values to the + # provided one; no INSERT should be attempted. + with self.assertNumQueries(1): + self.a1.publications.add(str(self.p1.pk)) + self.assertEqual(self.a1.publications.get(), self.p1) + @skipUnlessDBFeature('supports_ignore_conflicts') def test_slow_add_ignore_conflicts(self): manager_cls = self.a1.publications.__class__