使用__getattr__更改Django模型的行为 [英] Changing the behaviour of a Django model with __getattr__
问题描述
我正在尝试更改Django模型的行为,以允许我直接从父级访问外键的属性,例如
I'm trying to change the behaviour of a Django model to allow me to access a foreign key's properties directly from the parent, e.g.
cache.part_number
vs
cache.product.part_number
我尝试覆盖 __ getattr __
方法如下,但是当我尝试访问外键的属性时,我得到一个递归错误
I've tried overriding the __getattr__
method as follows, but I get a recursion error when I try to access the foreign key's properties
class Product(models.Model):
part_number = models.CharField(max_length=10)
...
class Cache(models.Model):
product = models.ForeignKey(Product)
...
def __getattr__(self, name):
value = getattr(self.product, name, None)
if value:
return value
else:
raise AttributeError
我做错了什么?
推荐答案
code> __ getattr __ 方法:
Consider the code inside your __getattr__
method:
value = getattr(self.product, name, None)
尝试猜测 self.product
被调用。我会给你一个线索:它涉及到调用 __ getattr __
。 文档具有以下详细信息:
Try guessing what happens when self.product
is invoked. I'll give you a clue: it involves a call to __getattr__
. The documentation has the details:
当属性查找在常用位置找不到属性时调用(即,它不是实例属性,也不是在类的树中找到的)。 name是属性名称。此方法应该返回(计算)属性值或引发AttributeError异常。
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
你想知道 .product
解析为正确的产品
实例,即使您未将其设置在任何位置吗?
Have you wondered how self.product
resolves to the correct Product
instance, even though you are not setting it anywhere?
请注意,如果通过正常机制找到属性,
__ getattr __()
Django做了一些涉及拦截的魔法,你猜到了, __ getattr __
。从而 self
自动以属性产品
结束。因为你正在覆盖 __ getattr __
方法,Django的魔法停止工作,你的版本被使用。由于 self.product
不是实例属性,因此会再次调用 __ getattr __
,等等,无限循环。
Django does some magic that involves intercepting, you guessed it, __getattr__
. Thereby self
automatically ends up with an attribute product
. Since you are overriding the __getattr__
method, Django's magic ceases to work and your version is used. Since self.product
is not an instance attribute, __getattr__
is called again, and again and so on, leading to an infinite loop.
你最好使用 property
。
You'd be better off using a property
to achieve this.
class Cache(models.Model):
product = models.ForeignKey(Product)
...
def _get_part_number(self):
part_number = self.product.part_number
if not part_number:
raise AttributeError
return part_number
part_number = property(_get_part_number)
这篇关于使用__getattr__更改Django模型的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!