1

Django 1.4でModelクラスの getattrをオーバーライドする適切な方法は何ですか?

次のようなモデル構造があります。

class Main(models.Model):
    [blah]

class Detail(models.Model):
   main = models.ForeignKey(Main)
   name = models.CharField(max_length=255)
   value= models.CharField(max_length=255)

メインをオーバーライドしました。getattr _ を使用して、Detail レコードを通常の Main 属性であるかのように参照できました。たとえば、次のような単純なメタモデル パターン

>>> m = Main.objects.create()
>>> Detail.objects.create(main=m, name='name', value='value')
>>> print m.name
'value'

これを行うには、1.4 より前のgetattrは次のようになりました。

def __getattr__(self, attrname):
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]

1.4にアップグレードするまで、これは完全に機能しました。これで、すべてのタイプの「属性 X が存在しません」というエラーが表示されます。次のようなことを試しましたが、うまくいきませんでした。特に、Django が ForeignKey 参照用に生成する「_*_cache」属性と競合するようです。

def __getattr__(self, attrname):
    try:
        return super(Main, self).__getattr__(attrname)
    except AttributeError:
        pass
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]

これを解決するにはどうすればよいですか?

4

2 に答える 2

1

__getattr__新しいモデル コードを調べてみると、バックエンドが大幅に変更されたようで、モデル クラスをオーバーライドする必要がなくなりました。代わりにobject.__getattribute__、基本モデルが継承する を呼び出す必要があります。ただし、Django はキャッシュされたデータを特別な属性に格納するため、適切に処理する必要があります。

私の新しい__getattr__ものは次のようになります。

def __getattr__(self, attrname):
    try:
        return super(Main, self).__getattribute__(attrname)
    except AttributeError:
        if attrname.startswith('_prefetched'):
            raise
    qs = self.details.filter(name=attrname)
    c = len(qs)
    if c == 0:
        raise AttributeError
    elif c == 1:
        return qs[0].value
    else:
        return [d.value for d in qs]
于 2012-06-05T18:03:22.337 に答える
1

私はこれを試していませんが、うまくいく__getattribute__()かもしれません:

class Main(models.Model):
    def __getattribute__(self, attrname):
        try:
            return super(Main, self).__getattribute__(attrname)
        except AttributeError:
            try:
                return self.__getattr__(attrname)
            except AttributeError:
                # do your database accessing

しかし、クリス・プラットが言ったように、これは少し効率的ではありません。属性のキャッシュを検討することをお勧めします。

于 2012-06-05T18:04:16.503 に答える