Code

Ticket #14368: 14368.patch

File 14368.patch, 3.4 KB (added by gruszczy, 4 years ago)
  • django/db/models/fields/related.py

     
    254254                    raise ValueError('Cannot assign "%r": instance is on database "%s", value is on database "%s"' % 
    255255                                        (value, instance._state.db, value._state.db)) 
    256256 
    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)) 
     257        if value is not None: 
     258            # Set the value of the related field to the value of the related object's related field 
     259            setattr(value, self.related.field.attname, getattr(instance, self.related.field.rel.get_related_field().attname)) 
     260     
     261            # Since we already know what the related object is, seed the related 
     262            # object caches now, too. This avoids another db hit if you get the 
     263            # object you just set. 
     264            setattr(instance, self.cache_name, value) 
     265            setattr(value, self.related.field.get_cache_name(), instance) 
     266        else: 
     267            value = getattr(instance, self.related.var_name, None) 
     268            if value is not None: 
     269                setattr(value, self.related.field.name, None) 
     270            try: 
     271                delattr(instance, self.cache_name) 
     272            except AttributeError: 
     273                pass 
    259274 
    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) 
    265  
    266275class ReverseSingleRelatedObjectDescriptor(object): 
    267276    # This class provides the functionality that makes the related-object 
    268277    # managers available as attributes on a model class, for fields that have 
  • tests/modeltests/one_to_one/tests.py

     
     1from django.test import TestCase 
     2 
     3from models import First, Second 
     4 
     5class OneToOneTestCase(TestCase): 
     6     
     7    def test_set_related_to_none(self): 
     8        # regression test for #14368 
     9        first = First.objects.create() 
     10        second = Second.objects.create() 
     11        first.second = second 
     12        first.second = None 
     13        self.assertRaises(Second.DoesNotExist, getattr, first, 'second') 
     14        self.assert_(second.first is None) 
  • tests/modeltests/one_to_one/models.py

     
    4646    def __unicode__(self): 
    4747        return u"Multimodel %s" % self.name 
    4848 
     49class First(models.Model): 
     50    pass 
     51 
     52class Second(models.Model): 
     53  first = models.OneToOneField(First, null=True) 
     54 
    4955__test__ = {'API_TESTS':""" 
    5056# Create a couple of Places. 
    5157>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') 
     
    190196...         print "Fail with %s" % type(e) 
    191197Pass 
    192198>>> transaction.savepoint_rollback(sid) 
    193  
    194199"""}