使用__getattr__更改Django模型的行为 [英] Changing the behaviour of a Django model with __getattr__

查看:341
本文介绍了使用__getattr__更改Django模型的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试更改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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆