9

我在网上看到过人们使用__getattr__Django 模型的例子,但每当我尝试时都会出错。(Django 1.2.3)

__getattr__在普通物体上使用时没有任何问题。例如:

class Post(object):
     def __getattr__(self, name):
         return 42

工作得很好...

 >>> from blog.models import Post
 >>> p = Post()
 >>> p.random
 42

现在,当我尝试使用 Django 模型时:

from django.db import models
class Post(models.Model):
     def __getattr__(self, name):
         return 42

并在解释器上进行测试:

 >>> from blog.models import Post
 >>> p = Post()
 ERROR: An unexpected error occurred while tokenizing input The

以下回溯可能已损坏或无效错误消息是:('EOF in multi-line statement', (6, 0))

-------------------------------------------------- ------------------------- TypeError
Traceback(最近一次调用最后一次)

/Users/josh/project/ in ()

/Users/josh/project/lib/python2.6/site-packages/django/db/models/base.pyc in init (self, *args, **kwargs) 338 if kwargs: 339 raise TypeError("'%s ' 是此函数的无效关键字参数" % kwargs.keys()[0]) --> 340 signals.post_init.send(sender=self.class , instance=self) 341 342 def repr (self):

/Users/josh/project/lib/python2.6/site-packages/django/dispatch/dispatcher.pyc in send(self, sender, **named) 160 161 for self._live_receivers(_make_id(sender)) 中的接收者: --> 162 response = receiver(signal=self, sender=sender, **named) 163 response.append((receiver, response)) 164 返回响应

/Users/josh/project/python2.6/site-packages/photologue/models.pyc in add_methods(sender, instance, signal, *args, **kwargs) 728 """ 729 if hasattr(instance, 'add_accessor_methods') : --> 730 instance.add_accessor_methods() 731 732 # 将 add_accessor_methods 函数连接到 post_init 信号

TypeError:“int”对象不可调用

有人可以解释发生了什么吗?


编辑:我在示例中可能过于抽象,这里有一些更接近我在网站上实际使用的代码:

class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField()
    date_published = models.DateTimeField()
    content = RichTextField('Content', blank=True, null=True)
    # Etc...

Class CuratedPost(models.Model):
    post = models.ForeignKey('Post')
    position = models.PositiveSmallIntegerField()

    def __getattr__(self, name):
        ''' If the user tries to access a property of the CuratedPost, return the property of the Post instead...  '''
        return self.post.name

    # Etc...

虽然我可以为 Post 类的每个属性创建一个属性,但这会导致大量代码重复。此外,这意味着每当我添加或编辑 Post 类的属性时,我都必须记住对 CuratedPost 类进行相同的更改,这似乎是代码腐烂的秘诀。

4

2 回答 2

7

使用 __getattr__ 时必须小心。只拦截你知道的,让基类处理你不知道的。

第一步是,你可以使用属性来代替吗?如果你想要一个返回 42 的“随机”属性,那么这更安全:

class Post(...):
  @property
  def random(self):
    return 42

如果你想让“random_*”(如“random_1”、“random_34”等)做某事,那么你必须像这样使用__getattr__:

class Post(...):
  def __getattr__(self, name):
    if name.startswith("random_"):
      return name[7:]
    return super(Post, self).__getattr__(name)
于 2011-01-08T14:18:00.550 回答
0

Django 在模型首次初始化时发送某些信号(即,通过加载 shell) - 通过使调用__getattr始终返回一个整数,您已经以 Django 信号不期望的方式修改了代码(因此,他们正在打破)。

如果你想这样做,也许可以这样尝试:

def __getattr__(self, attr):
  if hasattr(self, attr):
    return super(MyModel, self).__getattr__(attr)
  return 42
于 2011-01-07T21:16:59.040 回答