【问题标题】:Appropriate way to override Model __getattr__ in 1.4在 1.4 中覆盖 Model __getattr__ 的适当方法
【发布时间】:2012-06-05 14:20:12
【问题描述】:

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

我的模型结构如下:

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]

我该如何解决这个问题?

【问题讨论】:

  • 现在是停下来问问自己的好时机:你为什么要使用 H-E-double-hockey-sticks 那个?它不仅看起来像一个肮脏的 hack,而且效率也非常低,每次访问实例上的属性时都会生成数据库查询。你甚至没有缓存任何东西。
  • 诚然,我的情况很不寻常。简而言之,我的模型允许用户定义自己的自定义模型。添加缓存是微不足道的,为了简单起见,我省略了。

标签: python django django-models


【解决方案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]

【讨论】:

    【解决方案2】:

    我还没有尝试过,但__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 所说,这效率不高。您可能需要考虑缓存您的属性。

    【讨论】:

    • getattr(self, name) 会调用self.__getattribute__(name),导致无限递归。
    • 这个原因RuntimeError: maximum recursion depth exceeded
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    相关资源
    最近更新 更多