Fixed #11811 -- Data-loss bug in queryset.update.

It's now forbidden to call queryset.update(field=instance) when instance
hasn't been saved to the database ie. instance.pk is None.
This commit is contained in:
Aymeric Augustin 2013-09-06 17:13:51 -05:00
parent 73f38eb4d1
commit b4cd8169de
3 changed files with 15 additions and 1 deletions

View File

@ -768,6 +768,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):

View File

@ -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)

View File

@ -15,6 +15,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 .models import (
Annotation, Article, Author, Celebrity, Child, Cover, Detail, DumbCategory,
@ -969,7 +970,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, ['<NamedCategory: NamedCategory object>'])
self.assertQuerysetEqual(q, ['<NamedCategory: Generic>'])
def test_ticket_10790_4(self):
# Querying across m2m field should not strip the m2m table from join.
@ -1279,6 +1280,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 <NamedCategory: Other> '
'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