2011-01-07 8 views
6

Djangoモデルで__getattr__を使用している人のオンラインサンプルを見ましたが、試してみるとエラーが発生します。 (Django 1.2.3)Djangoモデルで__getattr__を使用できないのはなぜですか?

通常のオブジェクトに__getattr__を使用しているときに問題はありません。

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

作品だけで罰金...今私はDjangoのモデルとそれをしようとすると、

>>> from blog.models import Post 
>>> p = Post() 
>>> p.random 
42 

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

誰かが何を行っているのか説明できますかどう?


EDIT:

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クラスに同じ変更を行うことを忘れないでください。

+2

本当に "return self.post.name"ですか? "return getattr(self.post、name)"となるはずです。 –

+0

コードは – Joshmaker

答えて

0

Djangoはモデルが最初に(シェルをアップロードすることによって、IE)を初期化するとき、特定の信号を送る - __getattrへの呼び出しは常に整数を返すようにそれを行うことによって、あなたはDjangoの信号が「werenような方法でコードを変更しました期待している(したがって、彼らは壊れている)。

あなたはこれをしたい場合は、多分それをこのようにしてみてください:

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__"が必要です。 –

+1

そして、実際には、\ _ \ _ getattr \ _ \ _はattrが\ _ \ _ dict \ _ \ _にない場合にのみ呼び出されます。 –

+1

@Andrew:あなたは '__getattribute__' – Cameron

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) 
+0

私の記事で使用した例では、Djangoモデルオブジェクトを拡張すると、__getattr__プロパティの非常に簡単なアプリケーションでもブレークすることが示されています。オリジナルの投稿を更新して、実際に使用するものに近いものを追加しました。 – Joshmaker

+2

models.Modelに '__getattr__'がないので、' super(Post、self).__ getattr __(...) 'が例外をスローするように、これはDjangoで動作するとは思いません。 – Cerin

+1

試しましたか? Pythonはデフォルトの__getattr__を提供しているので、問題はありません。 –

関連する問題