1

在 Django 1.4中覆盖 Model 类的 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)

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

>>> 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]

我该如何解决这个问题?

4

2 回答 2

1

挖掘新的模型代码,似乎后端已经发生了很大的变化,因此模型类不再__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]
于 2012-06-05T18:03:22.337 回答
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

但正如 Chris Pratt 所说,这效率不高。您可能需要考虑缓存您的属性。

于 2012-06-05T18:04:16.503 回答