为什么我不能将__getattr__与Django模型一起使用?

Jos*_*ker 9 python django django-models getattr

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

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

class Post(object):
     def __getattr__(self, name):
         return 42
Run Code Online (Sandbox Code Playgroud)

工作得很好......

 >>> from blog.models import Post
 >>> p = Post()
 >>> p.random
 42
Run Code Online (Sandbox Code Playgroud)

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

from django.db import models
class Post(models.Model):
     def __getattr__(self, name):
         return 42
Run Code Online (Sandbox Code Playgroud)

并在解释器上测试它:

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

跟踪回溯可能已损坏或无效错误消息为:('多行语句中的EOF',(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如果kwargs:339引发TypeError("'%s '是这个函数"%kwargs.keys()[0])无效的关键字参数- > 340 signals.post_init.send(发件人=自我.,实例=自我)341 342 DEF 再版(个体):

/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响应=接收者(信号=自己,发送者=发送者,**命名)163 answers.append((接收者,响应))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...
Run Code Online (Sandbox Code Playgroud)

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

And*_*lke 6

必须小心使用__getattr__.只拦截你所知道的,让基类处理你不知道的事情.

第一步是,您可以使用房产吗?如果你想要一个返回42的"随机"属性,那么这样更安全:

class Post(...):
  @property
  def random(self):
    return 42
Run Code Online (Sandbox Code Playgroud)

如果你想要"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)
Run Code Online (Sandbox Code Playgroud)

  • 我不相信这会与Django一起使用,因为models.Model没有`__getattr__`,所以你的`super(Post,self).__ getattr __(...)`应该抛出异常. (2认同)

gir*_*uid 0

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

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

def __getattr__(self, attr):
  if hasattr(self, attr):
    return super(MyModel, self).__getattr__(attr)
  return 42
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这也不起作用,因为仅当 attr 不在 \_\_dict\_\_ 中时才调用 \_\_getattr\_\_ (2认同)