Django:AuditTrail &惰性关系

发布于 2024-08-03 03:54:54 字数 896 浏览 6 评论 0原文

我一直在尝试修改 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_lated_field() 调用将失败,因为 field.rel.to 是一个包含相关模型名称的字符串,而不是模型实例。

我不知道该怎么做才能解决这个问题。在开始复制字段之前,我是否必须确定模型具有哪些依赖项,并等到它们全部准备就绪?关于解决这个问题的最佳方法有什么想法吗?

I've been trying to modify the AuditTrail code so that it does not copy ForeignKey fields, but rather copies the related field (ie I don't want a foreign key on my database table for the audit model).

I've written a copy_field function that looks like so:

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

This code is run when the model that has the AuditTrail attribute is prepared (via the class_prepared signal).

However, this runs into problems when a ForeignKey is related to a field on a model that has not been prepared yet - the get_related_field() call will fail, because field.rel.to is a string containing the name of the related model, rather than a model instance.

I'm at a loss of what to do to work around this. Do I have to determine what dependencies a model has, and wait until they have all been prepared, before I start copying fields? Any ideas about the best way to go about this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开柳相依 2024-08-10 03:54:54

我最终做的是列出模型具有的所有依赖项(通过确定规范的应用程序/名称对;从 django.db.models.fields.lated 复制一些代码来确定这一点)并修改我的 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)

What I ended up doing was to list all the dependencies the model had (by determining a canoncial app/name pair; copying some code from django.db.models.fields.related to determine this) and modifying my class_prepared signal handler to listen to all models rather than just my target model.

When the handler recognized a model in my dependencies list, it would remove it from the list and check if the list was empty; if it was, it is ok to create the audit model. Important note was to disconnect the class_prepared handler before creating the model, else I encountered an infinite recursion (alternatively I could have gated the handler more specifically).

    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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文