This one has me baffled. Consider the following Django models - representing zookeepers and the cages at the zoo that they are responsible for cleaning:
class Zookeeper(moodels.Model):
name = models.CharField(max_length=40)
class Cage(models.Model):
zookeeper = models.ForeignKey(Zookeeper)
Now suppose I want to connect a receiver to the Cage
's post_init
signal:
@receiver(models.signals.post_init, sender=Cage)
def on_cage_init(instance, **kwargs):
print instance.zookeeper
As expected, this raises an exception since the Cage
has not yet been assigned to a Zookeeper
. Consider the following modification to the body of the receiver:
print getattr(instance, 'zookeeper', 'No Zookeeper')
One would expect this to print "No Zookeeper" since one has not been assigned to the instance. Instead, an exception is raised:
Traceback (most recent call last):
File "../zoo/models.py", line 185, in on_cage_init
print getattr(instance, 'zookeeper', 'No Zookeeper')
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 324, in __get__
"%s has no %s." % (self.field.model.__name__, self.field.name))
DoesNotExist: Cage has no zookeeper.
Why is it raising an exception? Isn't getattr()
supposed to return the provided default value if the attribute does not exist? I can prove that the attribute does not exist with:
print hasattr(instance, 'zookeeper')
...which prints False
.
ObjectDoesNotExist
by instead catchingZookeeper.DoesNotExist
. – Androclinium