9

Django モデルを使用している人々の例をオンラインで見たことがありますが__getattr__、試行するたびにエラーが発生します。(ジャンゴ 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 in multi-line statement', (6, 0))

-------------------------------------------------- ------------------------- TypeError
トレースバック (最新の呼び出しが最後)

/Users/josh/project/ () 内

/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 ' はこの関数の無効なキーワード引数です" % kwargs.keys()[0]) --> 340 signal.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 receive in self._live_receivers(_make_id(sender)): --> 162 応答 = 受信者 (信号 = 自己、送信者 = 送信者、**名前付き) 163 応答.追加 ((受信者、応答)) 164 返信応答

/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 # add_accessor_methods 関数を post_init シグナルに接続します

TypeError: 'int' オブジェクトは呼び出し可能ではありません

誰かが何が起こっているのか説明できますか?


編集: 例では抽象的すぎたかもしれません。Web サイトで実際に使用するコードに近いコードを次に示します。

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 クラスに同じ変更を加えることを覚えておく必要があり、これはコード腐敗のレシピのようです。

4

2 に答える 2

7

__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)
于 2011-01-08T14:18:00.550 に答える
0

Djangoは、モデルが最初に初期化されるときに(つまり、シェルをロードすることによって)特定のシグナルを送信します-呼び出しが__getattr常に整数を返すようにすることで、Djangoシグナルが予期していなかった方法でコードを変更しました(したがって、 、彼らは壊れています)。

これを実行したい場合は、次の方法で試してください。

def __getattr__(self, attr):
  if hasattr(self, attr):
    return super(MyModel, self).__getattr__(attr)
  return 42
于 2011-01-07T21:16:59.040 に答える