Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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.
  • Loading branch information...
commit b4cd8169de604943f8aaee3666282c95e650e5f4 1 parent 73f38eb
Aymeric Augustin authored September 06, 2013
2  django/db/models/base.py
@@ -768,6 +768,8 @@ def _get_next_or_previous_in_order(self, is_next):
768 768
         return getattr(self, cachename)
769 769
 
770 770
     def prepare_database_save(self, unused):
  771
+        if self.pk is None:
  772
+            raise ValueError("Unsaved model instance %r cannot be used in an ORM query." % self)
771 773
         return self.pk
772 774
 
773 775
     def clean(self):
4  tests/queries/models.py
@@ -17,9 +17,13 @@ class ProxyCategory(DumbCategory):
17 17
     class Meta:
18 18
         proxy = True
19 19
 
  20
+@python_2_unicode_compatible
20 21
 class NamedCategory(DumbCategory):
21 22
     name = models.CharField(max_length=10)
22 23
 
  24
+    def __str__(self):
  25
+        return self.name
  26
+
23 27
 @python_2_unicode_compatible
24 28
 class Tag(models.Model):
25 29
     name = models.CharField(max_length=10)
10  tests/queries/tests.py
@@ -15,6 +15,7 @@
15 15
 from django.db.models.sql.datastructures import EmptyResultSet
16 16
 from django.test import TestCase, skipUnlessDBFeature
17 17
 from django.test.utils import str_prefix
  18
+from django.utils import six
18 19
 
19 20
 from .models import (
20 21
     Annotation, Article, Author, Celebrity, Child, Cover, Detail, DumbCategory,
@@ -969,7 +970,7 @@ def test_ticket_10790_3(self):
969 970
         q = NamedCategory.objects.filter(tag__parent__isnull=True)
970 971
         self.assertTrue(str(q.query).count('INNER JOIN') == 1)
971 972
         self.assertTrue(str(q.query).count('LEFT OUTER JOIN') == 1)
972  
-        self.assertQuerysetEqual( q, ['<NamedCategory: NamedCategory object>'])
  973
+        self.assertQuerysetEqual(q, ['<NamedCategory: Generic>'])
973 974
 
974 975
     def test_ticket_10790_4(self):
975 976
         # Querying across m2m field should not strip the m2m table from join.
@@ -1279,6 +1280,13 @@ def setUp(self):
1279 1280
         Item.objects.create(name='i1', created=datetime.datetime.now(), note=n1, creator=self.a1)
1280 1281
         Item.objects.create(name='i2', created=datetime.datetime.now(), note=n1, creator=self.a3)
1281 1282
 
  1283
+    def test_ticket11811(self):
  1284
+        unsaved_category = NamedCategory(name="Other")
  1285
+        with six.assertRaisesRegex(self, ValueError,
  1286
+                'Unsaved model instance <NamedCategory: Other> '
  1287
+                'cannot be used in an ORM query.'):
  1288
+            Tag.objects.filter(pk=self.t1.pk).update(category=unsaved_category)
  1289
+
1282 1290
     def test_ticket14876(self):
1283 1291
         # Note: when combining the query we need to have information available
1284 1292
         # about the join type of the trimmed "creator__isnull" join. If we

0 notes on commit b4cd816

Please sign in to comment.
Something went wrong with that request. Please try again.