Ticket #13839: 13839-4.patch
File 13839-4.patch, 4.7 KB (added by , 13 years ago) |
---|
-
django/db/models/fields/related.py
249 249 if instance is None: 250 250 return self 251 251 try: 252 re turngetattr(instance, self.cache_name)252 related = getattr(instance, self.cache_name) 253 253 except AttributeError: 254 254 params = {'%s__pk' % self.related.field.name: instance._get_pk_val()} 255 rel_obj = self.get_query_set(instance=instance).get(**params) 256 setattr(instance, self.cache_name, rel_obj) 257 return rel_obj 255 try: 256 related = self.get_query_set(instance=instance).get(**params) 257 except self.related.model.DoesNotExist: 258 related = None 259 else: 260 setattr(related, self.related.field.get_cache_name(), instance) 261 setattr(instance, self.cache_name, related) 262 if related is None: 263 raise self.related.model.DoesNotExist 264 else: 265 return related 258 266 259 267 def __set__(self, instance, value): 260 268 if instance is None: … … 331 339 def __get__(self, instance, instance_type=None): 332 340 if instance is None: 333 341 return self 334 335 342 try: 336 343 return getattr(instance, self.cache_name) 337 344 except AttributeError: … … 347 354 else: 348 355 params = {'%s__exact' % self.field.rel.field_name: val} 349 356 qs = self.get_query_set(instance=instance) 357 # Assuming the database enforces foreign keys, this won't fail. 350 358 rel_obj = qs.get(**params) 351 359 setattr(instance, self.cache_name, rel_obj) 352 360 return rel_obj … … 385 393 # populated the cache, then we don't care - we're only accessing 386 394 # the object to invalidate the accessor cache, so there's no 387 395 # need to populate the cache just to expire it again. 388 related = getattr(instance, self. field.get_cache_name(), None)396 related = getattr(instance, self.cache_name, None) 389 397 390 398 # If we've got an old related object, we need to clear out its 391 399 # cache. This cache also might not exist if the related object … … 405 413 setattr(instance, self.field.attname, val) 406 414 407 415 # Since we already know what the related object is, seed the related 408 # object cache now, too. This avoids another db hit if you get the416 # object caches now, too. This avoids another db hit if you get the 409 417 # object you just set. 410 setattr(instance, self.field.get_cache_name(), value) 418 setattr(instance, self.cache_name, value) 419 if value is not None and not self.field.rel.multiple: 420 setattr(value, self.field.related.get_cache_name(), instance) 411 421 412 422 class ForeignRelatedObjectsDescriptor(object): 413 423 # This class provides the functionality that makes the related-object -
tests/regressiontests/select_related_onetoone/tests.py
79 79 p1 = Product.objects.create(name="Django Plushie", image=im) 80 80 p2 = Product.objects.create(name="Talking Django Plushie") 81 81 82 self.assertEqual(len(Product.objects.select_related("image")), 2) 82 with self.assertNumQueries(1): 83 result = sorted(Product.objects.select_related("image"), key=lambda x: x.name) 84 self.assertEqual([p.name for p in result], ["Django Plushie", "Talking Django Plushie"]) 85 86 self.assertEqual(p1.image, im) 87 # Check for ticket #13839 88 self.assertIsNone(p2.image) 89 90 def test_missing_reverse(self): 91 """ 92 Ticket #13839: select_related() should NOT cache None 93 for missing objects on a reverse 1-1 relation. 94 """ 95 with self.assertNumQueries(1): 96 user = User.objects.select_related('userprofile').get(username='bob') 97 with self.assertRaises(UserProfile.DoesNotExist): 98 user.userprofile 99 100 def test_nullable_missing_reverse(self): 101 """ 102 Ticket #13839: select_related() should NOT cache None 103 for missing objects on a reverse 0-1 relation. 104 """ 105 Image.objects.create(name="imag1") 106 107 with self.assertNumQueries(1): 108 image = Image.objects.select_related('product').get() 109 with self.assertRaises(Product.DoesNotExist): 110 image.product