1

フィールドをコピーせず、関連フィールドをコピーするようにAuditTrailコードを変更しようとしています(つまり、監査モデルのデータベーステーブルに外部キーが必要ありません)。ForeignKey

私はcopy_field次のような関数を作成しました。

def copy_field(field):
    while(isinstance(field, models.OneToOneField, models.ForeignKey)):
        field = field.rel.get_related_field()
    if isinstance(field, models.AutoField):
        f = models.IntegerField()
    else:
        f = copy(field)
    #...snip some adjusting of fs attributes...
    return f

このコードは、属性を持つモデルが(シグナルAuditTrailを介して)準備されるときに実行されます。class_prepared

ただし、これは、ForeignKeyがまだ準備されていないモデルのフィールドに関連している場合に問題が発生します。これは、モデルインスタンスではなく、関連するモデルの名前を含む文字列get_related_field()であるため、呼び出しは失敗します。field.rel.to

私はこれを回避するために何をすべきか途方に暮れています。モデルの依存関係を特定し、それらがすべて準備されるまで待ってから、フィールドのコピーを開始する必要がありますか?これについて行くための最良の方法について何かアイデアはありますか?

4

1 に答える 1

0

私が最終的にやったのは、モデルが持っていたすべての依存関係をリストすることでした (正規のアプリと名前のペアを決定し、これを決定するためにコードをコピーすることにより) 、ターゲット モデルだけでなくすべてのモデルをリッスンするようdjango.db.models.fields.relatedにシグナル ハンドラーを変更しました。class_prepared

ハンドラーが依存関係リスト内のモデルを認識すると、そのモデルをリストから削除し、リストが空かどうかを確認します。そうであれば、監査モデルを作成しても問題ありません。重要な注意点はclass_prepared、モデルを作成する前にハンドラーを切断することでした。そうしないと、無限再帰が発生しました (別の方法として、ハンドラーをより具体的にゲートすることもできました)。

    dependencies = []
    for field in cls._meta.local_fields:
        while isinstance(field, (models.OneToOneField, models.ForeignKey)):
            if isinstance(field.rel.to,basestring):
                dependencies.append(get_canonical(cls,field.rel.to))
                break
            else:
                field = field.rel.get_related_field()

    def _contribute(sender, **kwargs):
        key = (sender._meta.app_label, sender.__name__)
        if key in dependencies:
            dependencies.remove(key)
        if not dependencies:
            models.signals.class_prepared.disconnect(_contribute)
            model = create_audit_model(cls)

    models.signals.class_prepared.connect(_contribute, weak=False)
于 2009-09-02T07:19:57.683 に答える