Fixed #8467 -- Prevented crash when adding existent m2m relation with an invalid type.
This was an issue anymore on backends that allows conflicts to be ignored (Refs #19544) as long the provided values were coercible to the expected type. However on the remaining backends that don't support this feature, namely Oracle, this could still result in an IntegrityError. By attempting to coerce the provided values to the expected types in Python beforehand we allow the existing value set intersection in ManyRelatedManager._get_missing_target_ids to prevent the problematic insertion attempts. Thanks Baptiste Mispelon for triaging this old ticket against the current state of the master branch.
This commit is contained in:
parent
8cc711999a
commit
379bf1a2d4
|
@ -1064,7 +1064,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
||||||
(self.model._meta.object_name, obj)
|
(self.model._meta.object_name, obj)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
target_ids.add(obj)
|
target_ids.add(target_field.get_prep_value(obj))
|
||||||
return target_ids
|
return target_ids
|
||||||
|
|
||||||
def _get_missing_target_ids(self, source_field_name, target_field_name, db, target_ids):
|
def _get_missing_target_ids(self, source_field_name, target_field_name, db, target_ids):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Article, InheritedArticleA, InheritedArticleB, Publication, User,
|
Article, InheritedArticleA, InheritedArticleB, Publication, User,
|
||||||
|
@ -158,6 +158,14 @@ class ManyToManyTests(TestCase):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.a1.publications.add(self.p1, self.p2)
|
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')
|
@skipUnlessDBFeature('supports_ignore_conflicts')
|
||||||
def test_slow_add_ignore_conflicts(self):
|
def test_slow_add_ignore_conflicts(self):
|
||||||
manager_cls = self.a1.publications.__class__
|
manager_cls = self.a1.publications.__class__
|
||||||
|
|
Loading…
Reference in New Issue