为什么我不能在Django模型中使用__getattr__? [英] Why can't I use __getattr__ with Django models?

查看:110
本文介绍了为什么我不能在Django模型中使用__getattr__?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在线上看到了使用__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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆