在1.4中覆盖Model __getattr__的适当方法

时间:2012-06-05 14:20:13

标签: python django django-models

覆盖Model类的适当方法是什么 Django 1.4中的 getattr

我有一个模型结构,如:

class Main(models.Model):
    [blah]

class Detail(models.Model):
   main = models.ForeignKey(Main)
   name = models.CharField(max_length=255)
   value= models.CharField(max_length=255)

我覆盖了我的Main。 getattr _所以我可以引用Detail 记录好像它们是正常的主要属性。例如一个简单的元 模型模式如

>>> m = Main.objects.create()
>>> Detail.objects.create(main=m, name='name', value='value')
>>> print m.name
'value'

为此,我的1.4之前 getattr 看起来像是:

def __getattr__(self, attrname):
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]

这完美无缺,直到我升级到1.4。现在我得到了所有类型 “属性X不存在”错误。我试过像这样的东西 以下,但没有运气。它似乎特别与之相冲突 Django为ForeignKey引用生成的“_ * _ cache”属性。

def __getattr__(self, attrname):
    try:
        return super(Main, self).__getattr__(attrname)
    except AttributeError:
        pass
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

通过挖掘新的模型代码,似乎后端已经发生了很大的变化,因此Model类不再需要__getattr__来覆盖。相反,我需要调用基础模型继承的object.__getattribute__。但是,Django将缓存的数据存储在需要正确处理的特殊属性中。

我的新__getattr__现在看起来像是:

def __getattr__(self, attrname):
    try:
        return super(Main, self).__getattribute__(attrname)
    except AttributeError:
        if attrname.startswith('_prefetched'):
            raise
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]

答案 1 :(得分:1)

我没有尝试过,但__getattribute__()可能会有效:

class Main(models.Model):
    def __getattribute__(self, attrname):
        try:
            return super(Main, self).__getattribute__(attrname)
        except AttributeError:
            try:
                return self.__getattr__(attrname)
            except AttributeError:
                # do your database accessing

但正如克里斯普拉特所说,这不是有点效率。您可能需要考虑缓存属性。