diff --git a/django/db/models/base.py b/django/db/models/base.py index dfb4fae24c..33229f21f3 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -736,6 +736,8 @@ class Model(six.with_metaclass(ModelBase)): return getattr(self, cachename) def prepare_database_save(self, unused): + if self.pk is None: + raise ValueError("Unsaved model instance %r cannot be used in an ORM query." % self) return self.pk def clean(self): diff --git a/tests/queries/models.py b/tests/queries/models.py index 7248246261..99c04a1c9b 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -17,9 +17,13 @@ class ProxyCategory(DumbCategory): class Meta: proxy = True +@python_2_unicode_compatible class NamedCategory(DumbCategory): name = models.CharField(max_length=10) + def __str__(self): + return self.name + @python_2_unicode_compatible class Tag(models.Model): name = models.CharField(max_length=10) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index fbeadf726a..cffead7a52 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -13,6 +13,7 @@ from django.db.models.sql.where import WhereNode, EverythingNode, NothingNode from django.db.models.sql.datastructures import EmptyResultSet from django.test import TestCase, skipUnlessDBFeature from django.test.utils import str_prefix +from django.utils import six from django.utils import unittest from django.utils.datastructures import SortedDict @@ -957,7 +958,7 @@ class Queries1Tests(BaseQuerysetTest): q = NamedCategory.objects.filter(tag__parent__isnull=True) self.assertTrue(str(q.query).count('INNER JOIN') == 1) self.assertTrue(str(q.query).count('LEFT OUTER JOIN') == 1) - self.assertQuerysetEqual( q, ['']) + self.assertQuerysetEqual(q, ['']) def test_ticket_10790_4(self): # Querying across m2m field should not strip the m2m table from join. @@ -1267,6 +1268,13 @@ class Queries4Tests(BaseQuerysetTest): Item.objects.create(name='i1', created=datetime.datetime.now(), note=n1, creator=self.a1) Item.objects.create(name='i2', created=datetime.datetime.now(), note=n1, creator=self.a3) + def test_ticket11811(self): + unsaved_category = NamedCategory(name="Other") + with six.assertRaisesRegex(self, ValueError, + 'Unsaved model instance ' + 'cannot be used in an ORM query.'): + Tag.objects.filter(pk=self.t1.pk).update(category=unsaved_category) + def test_ticket14876(self): # Note: when combining the query we need to have information available # about the join type of the trimmed "creator__isnull" join. If we