为什么我不能在Django模型中使用__getattr__? [英] Why can't I use __getattr__ with Django models?
问题描述
我在线上看到了使用__getattr__
和Django模型的人们的例子,但是每当尝试尝试时,我都会出错. (Django 1.2.3)
I've seen examples online of people using __getattr__
with Django models, but whenever I try I get errors. (Django 1.2.3)
在普通对象上使用__getattr__
时,我没有任何问题.例如:
I don't have any problems when I am using __getattr__
on normal objects. For example:
class Post(object):
def __getattr__(self, name):
return 42
工作正常...
>>> from blog.models import Post
>>> p = Post()
>>> p.random
42
现在,当我尝试使用Django模型时:
Now when I try it with a Django model:
from django.db import models
class Post(models.Model):
def __getattr__(self, name):
return 42
并在解释器上对其进行测试:
And test it on on the interpreter:
>>> from blog.models import Post
>>> p = Post()
ERROR: An unexpected error occurred while tokenizing input The
以下追溯可能已损坏 或无效错误消息为:('EOF 在多行语句中',(6,0))
following traceback may be corrupted or invalid The error message is: ('EOF in multi-line statement', (6, 0))
--------------------------------------------------- ---------------------------- TypeError
追溯(最近一次通话结束)
--------------------------------------------------------------------------- TypeError
Traceback (most recent call last)
/Users/josh/project/ 在()
/Users/josh/project/ in ()
/用户/josh/project/lib/python2.6/site-packages/django/db/models/base.pyc 在 init (自身,* args,** kwargs)中 第338章 339引发TypeError('%s'是无效的关键字 此函数的参数% kwargs.keys()[0]) -> 340 signal.post_init.send(sender = self. class , 实例=自己) 341 342 def 代表(自己):
/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 在send(自己,sender,** named)中 160 161 for self._live_receivers(_make_id(sender)): -> 162响应=接收者(信号=自己,发送者=发送者, **命名) 第163回 164个回复
/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 在add_methods中(发件人,实例, 信号,* args,** kwargs) 728" 第729章真相大白 -> 730 instance.add_accessor_methods() 731 第732章 post_init信号
/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"对象不是 可通话的
TypeError: 'int' object is not callable
有人可以解释发生了什么事吗?
Can someone explain what is going on?
我可能在示例中太抽象了,下面是一些与我在网站上实际使用的代码更接近的代码:
I may have been too abstract in the examples, here is some code that is closer to what I actually would use on the website:
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类进行相同的更改,这似乎是代码腐烂的秘诀.
While I could create a property for each attribute of the Post class, that would lead to a lot of code duplication. Further more, that would mean anytime I add or edit a attribute of the Post class I would have to remember to make the same change to the CuratedPost class, which seems like a recipe for code rot.
推荐答案
使用__getattr__必须小心.仅拦截您所知道的内容,并让基类处理您不知道的内容.
One must be careful using __getattr__ . Only intercept what you know, and let the base class handle what you do not.
第一步是,您可以改用属性吗?如果您想要返回42的"random"属性,那么这会更安全:
The first step is, can you use a property instead? If you want a "random" attribute which return 42 then this is much safer:
class Post(...):
@property
def random(self):
return 42
如果您想让"random _ *"(例如"random_1","random_34"等)做某事,则必须使用__getattr__这样:
If you want "random_*" (like "random_1", "random_34", etc) to do something then you'll have to use __getattr__ like this:
class Post(...):
def __getattr__(self, name):
if name.startswith("random_"):
return name[7:]
return super(Post, self).__getattr__(name)
这篇关于为什么我不能在Django模型中使用__getattr__?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!