diff --git a/django/db/models/query.py b/django/db/models/query.py index fd531dd6d0..41c24c7a58 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -4,6 +4,7 @@ The main QuerySet implementation. This provides the public API for the ORM. import copy import itertools +import sys from django.db import connections, router, transaction, IntegrityError from django.db.models.fields import AutoField @@ -450,10 +451,12 @@ class QuerySet(object): return obj, True except IntegrityError, e: transaction.savepoint_rollback(sid, using=self.db) + exc_info = sys.exc_info() try: return self.get(**lookup), False except self.model.DoesNotExist: - raise e + # Re-raise the IntegrityError with its original traceback. + raise exc_info[1], None, exc_info[2] def latest(self, field_name=None): """ diff --git a/tests/modeltests/get_or_create/tests.py b/tests/modeltests/get_or_create/tests.py index 4cf44507c8..f98f0e63d8 100644 --- a/tests/modeltests/get_or_create/tests.py +++ b/tests/modeltests/get_or_create/tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from datetime import date +import traceback from django.db import IntegrityError from django.test import TestCase @@ -52,3 +53,14 @@ class GetOrCreateTests(TestCase): ManualPrimaryKeyTest.objects.get_or_create, id=1, data="Different" ) self.assertEqual(ManualPrimaryKeyTest.objects.get(id=1).data, "Original") + + # get_or_create should raise IntegrityErrors with the full traceback. + # This is tested by checking that a known method call is in the traceback. + # We cannot use assertRaises/assertRaises here because we need to inspect + # the actual traceback. Refs #16340. + try: + ManualPrimaryKeyTest.objects.get_or_create(id=1, data="Different") + except IntegrityError, e: + formatted_traceback = traceback.format_exc() + self.assertIn('obj.save', formatted_traceback) +