Ticket #9023: 9023.diff

File 9023.diff, 3.3 KB (added by jacob, 6 years ago)
  • django/db/models/fields/related.py

    diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
    index 419695b..f5d4fa3 100644
    a b class RelatedField(object): 
    112112
    113113    def do_related_class(self, other, cls):
    114114        self.set_attributes_from_rel()
    115         related = RelatedObject(other, cls, self)
     115        self.related = RelatedObject(other, cls, self)
    116116        if not cls._meta.abstract:
    117             self.contribute_to_related_class(other, related)
     117            self.contribute_to_related_class(other, self.related)
    118118
    119119    def get_db_prep_lookup(self, lookup_type, value):
    120120        # If we are doing a lookup on a Related Field, we must be
    class ReverseSingleRelatedObjectDescriptor(object): 
    271271                                (value, instance._meta.object_name,
    272272                                 self.field.name, self.field.rel.to._meta.object_name))
    273273
     274        # If we're setting the value of a OneToOneField to None, we need to clear
     275        # out the cache on any old related object. Otherwise, deleting the
     276        # previously-related object will also cause this object to be deleted,
     277        # which is wrong.
     278        if value is None:
     279            # Look up the previously-related object, which is still available
     280            # since we've not year cleared out the related field. This could
     281            # raise a DoesNotExist exception, which we need to ignore.
     282            try:
     283                related = getattr(instance, self.field.name, None)
     284            except self.field.rel.to.DoesNotExist:
     285                related = None
     286
     287            # If we've got an old related object, we need to clear out its
     288            # cache. This cache also might not exist if the related object
     289            # hasn't been accessed yet.
     290            if related:
     291                cache_name = '_%s_cache' % self.field.related.get_accessor_name()
     292                try:
     293                    delattr(related, cache_name)
     294                except AttributeError:
     295                    pass
     296
    274297        # Set the value of the related field
    275298        try:
    276299            val = getattr(value, self.field.rel.get_related_field().attname)
  • new file 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
    new file mode 100644
    index 0000000..b9b171b
    - +  
     1from django.test import TestCase
     2from regressiontests.one_to_one_regress.models import Place, UndergroundBar
     3
     4class OneToOneDeletionTests(TestCase):
     5    def test_reverse_relationship_cache_cascade(self):
     6        """
     7        Regression test for #9023: accessing the reverse relationship shouldn't
     8        result in a cascading delete().
     9        """
     10        place = Place.objects.create(name="Dempsey's", address="623 Vermont St")
     11        bar = UndergroundBar.objects.create(place=place, serves_cocktails=False)
     12       
     13        # The bug in #9023: if you access the one-to-one relation *before*
     14        # setting to None and deleting, the cascade happens anyway.
     15        place.undergroundbar
     16        bar.place = None
     17        bar.save()
     18        place.delete()
     19       
     20        self.assertEqual(Place.objects.all().count(), 0)
     21        self.assertEqual(UndergroundBar.objects.all().count(), 1)
     22       
     23 No newline at end of file
Back to Top