2011-01-07 86 views
6

我在網上看到過使用與Django模型的人的例子,但是每當我嘗試我會得到錯誤。 (Django 1.2.3)爲什麼我不能在Django模型中使用__getattr__?

當我在普通對象上使用__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 

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

有人可以解釋什麼是布萊恩g on?


編輯:我可以在例子已經過於抽象,這裏是一些代碼,接近我居然會在網站上使用:

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類進行相同的更改,這看起來像是代碼rot的配方。

+2

是真的「返回self.post.name」?它應該是「return getattr(self.post,name)」 – 2011-01-11 03:31:45

+0

確實,這就是代碼應該是 – Joshmaker 2011-01-11 17:24:17

回答

0

Django在模型第一次初始化時(即通過加載shell)發送特定的信號 - 通過使得對__getattr的調用總是返回一個整數,您已經以Django信號不被修改的方式修改代碼,期待(因此,他們正在打破)。

如果你想這樣做,也許嘗試這種方式:

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

這是不行的,因爲hasattr(self,attr)最終遞歸調用\ _ \ _ getattr \ _ \ __。您需要「attr in self .__ dict__」。 – 2011-01-08 14:08:58

5

人們必須使用__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) 
相關問題