Ticket #14368: ticket-14368.patch
File ticket-14368.patch, 4.4 KB (added by , 14 years ago) |
---|
-
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
a b 253 253 if not router.allow_relation(value, instance): 254 254 raise ValueError('Cannot assign "%r": instance is on database "%s", value is on database "%s"' % 255 255 (value, instance._state.db, value._state.db)) 256 # Since we already know what the related object is, seed the related 257 # object caches now, too. This avoids another db hit if you get the 258 # object you just set. 259 setattr(instance, self.cache_name, value) 260 setattr(value, self.related.field.name, instance) 261 else: 262 # update the cached related instance (if any) and clear the cache 263 try: 264 rel_obj = getattr(instance, self.cache_name) 265 except AttributeError: 266 pass 267 else: 268 delattr(instance, self.cache_name) 269 setattr(rel_obj, self.related.field.name, None) 256 270 257 # Set the value of the related field to the value of the related object's related field 258 setattr(value, self.related.field.attname, getattr(instance, self.related.field.rel.get_related_field().attname)) 259 260 # Since we already know what the related object is, seed the related 261 # object caches now, too. This avoids another db hit if you get the 262 # object you just set. 263 setattr(instance, self.cache_name, value) 264 setattr(value, self.related.field.get_cache_name(), instance) 271 if self.related.field.null: 272 # break the link to the existing value (if any) 273 filter_params = {self.related.field.name: instance._get_pk_val()} 274 update_params = {self.related.field.name: None} 275 db = router.db_for_write(self.related.model, instance=instance) 276 self.related.model._base_manager.using(db).filter(**filter_params).update(**update_params) 265 277 266 278 class ReverseSingleRelatedObjectDescriptor(object): 267 279 # This class provides the functionality that makes the related-object -
tests/regressiontests/one_to_one_regress/tests.py
diff --git a/tests/regressiontests/one_to_one_regress/tests.py b/tests/regressiontests/one_to_one_regress/tests.py
a b 128 128 Target.objects.exclude(pointer2=None), 129 129 [] 130 130 ) 131 132 def test_modify_related(self): 133 """ 134 Setting the reverse relationship of a O2O null field to a new instance 135 should succeed and remove the link from the current instance (if any). 136 """ 137 b1 = UndergroundBar.objects.create(place=self.p1, serves_cocktails=False) 138 b2 = UndergroundBar(serves_cocktails=True) 139 self.p1.undergroundbar = b2 140 b2.save() 141 self.assertEqual(UndergroundBar.objects.get(pk=b1.pk).place, None) 142 self.assertEqual(UndergroundBar.objects.get(pk=b2.pk).place, self.p1) 143 144 def test_unset_related(self): 145 """Regression test for #14368 [1] 146 147 Setting the reverse relationship of a O2O null field to None should 148 succeed and remove the link from the current instance (if any). 149 """ 150 bar = UndergroundBar.objects.create(place=self.p1, serves_cocktails=False) 151 self._unset_related(self.p1, bar) 152 153 def test_unset_related_after_set(self): 154 """Regression test for #14368 [2] 155 156 Setting the reverse relationship of a O2O null field to None should 157 succeed and remove the link from the current instance (if any). 158 159 In this test the related object is set to point to an instance before 160 set to None. 161 """ 162 bar = UndergroundBar(serves_cocktails=False) 163 self.p1.undergroundbar = bar 164 bar.save() 165 self._unset_related(self.p1, bar) 166 self.assertEqual(bar.place, None) 167 168 def _unset_related(self, place, undergroundbar): 169 self.assertEqual(UndergroundBar.objects.filter(place=place).count(), 1) 170 self.assertEqual(place.undergroundbar, undergroundbar) 171 place.undergroundbar = None 172 self.assertEqual(UndergroundBar.objects.filter(place=place).count(), 0) 173 self.assertRaises(UndergroundBar.DoesNotExist, getattr, place, 'undergroundbar')