我在网上看到了使用__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类进行相同的更改,这似乎是代码腐烂的一个方法。
答案 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