Django:AuditTrail&懒惰的关系

时间:2009-08-26 07:50:12

标签: django orm lazy-evaluation audit-trail

我一直在尝试修改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是一个字符串包含相关模型的名称,而不是模型实例。

我无法解决这个问题。在开始复制字段之前,我是否必须确定模型具有哪些依赖关系,并等到它们都准备好了?关于最佳方式的任何想法?

1 个答案:

答案 0 :(得分: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)