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

Why can't I use __getattr__ with Django models?

我在网上看到过一些人在使用django模型时使用__getattr__的例子,但每当我尝试时,都会出错。(姜戈1.2.3)

当我在普通对象上使用__getattr__时没有任何问题。例如:

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

工作很好…

1
2
3
4
 >>> from blog.models import Post
 >>> p = Post()
 >>> p.random
 42

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

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

在口译员身上进行测试:

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

following traceback may be corrupted
or invalid The error message is: ('EOF
in multi-line statement', (6, 0))

--------------------------------------------------------------------------- TypeError
Traceback (most recent call last)

/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' is an invalid keyword
argument for this function" %
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 receiver in self._live_receivers(_make_id(sender)):
--> 162 response = receiver(signal=self, sender=sender,
**named)
163 responses.append((receiver, response))
164 return responses

/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 # connect the add_accessor_methods function to the
post_init signal

TypeError: 'int' object is not
callable

有人能解释一下发生了什么事吗?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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类进行相同的更改,这看起来像是代码腐烂的秘诀。


用 getattr uu来照顾一个人。只有拦截你所知道的,让基地班级掌握你所不知道的。

第一步是,你能使用一个不动产吗?如果你想要一个"随机"的属性,42,这是非常安全的:

ZZU1

如果你想"random *"(like"random 1","random 34"等)做些什么,你就必须使用

1
2
3
4
5
class Post(...):
  def __getattr__(self, name):
    if name.startswith("random_"):
      return name[7:]
    return super(Post, self).__getattr__(name)


Django sends certain signals when the models a re first initiatized(IE,by loading up the shell)-by making it so calls to __getattralways return an integer,you chango signals were not expecting(and therefore,they're breaking).

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

1
2
3
4
def __getattr__(self, attr):
  if hasattr(self, attr):
    return super(MyModel, self).__getattr__(attr)
  return 42