{{{
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(models.Model):
place = models.OneToOneField(Place)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
}}}
Executing this, works just fine:
{{{
p = Place()
p.restaurant = None
}}}
But this:
{{{
p = Place()
r = getattr(p, 'restaurant', None)
p.restaurant = None
}}}
…raises an AttributeError:
{{{
AttributeError Traceback (most recent call
last)
<ipython-input-4-c4df23702cac> in <module>()
----> 1 p.restaurant = None
.../lib/python3.5/site-
packages/django/db/models/fields/related_descriptors.py in __set__(self,
instance, value)
435 else:
436 delattr(instance, self.cache_name)
--> 437 setattr(rel_obj, self.related.field.name, None)
438 elif not isinstance(value, self.related.related_model):
439 # An object must be an instance of the related class.
AttributeError: 'NoneType' object has no attribute 'place'
}}}
The above is with Python 3.5.3 and Django 1.11.6, although user "knbk" on
#django said that they reproduced it in master.
--
Ticket URL: <https://code.djangoproject.com/ticket/28742>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* stage: Unreviewed => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:1>
Comment (by Josh Schneier):
Another way of reproducing this is with
{{{#!python
def test_getattr_getter(self):
place = Place()
try:
place.restaurant
except Restaurant.DoesNotExist:
place.restaurant = None
}}}
The problem is that we are caching the return of
`Restaurant.DoesNotExist`. Removing the caching triggers a regression test
for #17439. I saw that Aymeric closed that one quite a while ago so I'd be
interested on some additional thoughts.
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:2>
* owner: nobody => Paulo
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:3>
Comment (by Paulo):
PR: https://github.com/django/django/pull/9305
I think the regression came from
https://github.com/django/django/commit/384ddbec1b73a4636f234da3894fde8f8420bb63
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:4>
* has_patch: 0 => 1
Comment:
The test in the PR is failing as far back as I tested (Django 1.7, note:
you have to update the models according to
7fe554b2a3d72d0142e5c9e97efbd0a672c2d790 there).
Are you seeing a regression from an older version of Django?
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:5>
Comment (by Paulo):
I didn't test that far back.
Only traced the AttributeError to the commit above, before that I assume a
ValueError was raised because setting None was just not allowed.
So is not really a regression.
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:6>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"fcfcf8aae470d893b0d2ef176434461edf9e9c4d" fcfcf8a]:
{{{
#!CommitTicketReference repository=""
revision="fcfcf8aae470d893b0d2ef176434461edf9e9c4d"
Fixed #28742 -- Fixed AttributeError crash when assigning None to cached
reverse relations.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:7>
Comment (by Tim Graham <timograham@…>):
In [changeset:"f2d5417d3b7a4012298fcffc6eab618cc09d0344" f2d5417d]:
{{{
#!CommitTicketReference repository=""
revision="f2d5417d3b7a4012298fcffc6eab618cc09d0344"
[2.0.x] Fixed #28742 -- Fixed AttributeError crash when assigning None to
cached reverse relations.
Backport of fcfcf8aae470d893b0d2ef176434461edf9e9c4d from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/28742#comment:8>