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

时间:2011-01-07 21:12:35

标签: python django django-models getattr

我在网上看到了使用__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   在多行语句',(6,0))

     

----------------------------------------------- ---------------------------- TypeError
  追溯(最近的呼叫最后一次)

     

/用户/约什/项目/   in()

     

/Users/josh/project/lib/python2.6/site-packages/django/db/models/base.pyc   在 init (self,* args,** kwargs)       如果kwargs:       339引发TypeError(“'%s'是无效的关键字   这个函数的参数“%   kwargs.keys()[0])    - > 340 signals.post_init.send(sender = self。 class ,   例如=个体经营)       341       342 def repr (自我):

     

/Users/josh/project/lib/python2.6/site-packages/django/dispatch/dispatcher.pyc   发送(自我,发件人,**命名)       160       161为self._live_receivers(_make_id(sender))中的接收者:    - > 162响应=接收者(信号=自己,发送者=发送者,   **命名)       163 answers.append((接收者,回应))       164回复

     

/Users/josh/project/python2.6/site-packages/photologue/models.pyc   在add_methods中(发件人,实例,   信号,* 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类进行相同的更改,这似乎是代码腐烂的一个方法。

2 个答案:

答案 0 :(得分:6)

必须小心使用__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)

答案 1 :(得分:0)

Django在模型首次初始化时发送某些信号(即通过加载shell) - 通过调用__getattr总是返回一个整数,你已经以Django的方式修改了代码信号没有预期(因此,它们正在破裂)。

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

def __getattr__(self, attr):
  if hasattr(self, attr):
    return super(MyModel, self).__getattr__(attr)
  return 42