侧边栏壁纸
  • 累计撰写 214 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

Python跨文件的循环引用问题

barwe
2024-09-05 / 0 评论 / 0 点赞 / 229 阅读 / 997 字
温馨提示:
本文最后更新于 2024-09-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Python 前向引用的问题 中类 AuditLog 和类 AuditDetail 是直接放置在同一个文件中的,此时可直接通过 字符串注解 来解决循环引用的问题。

如果类 AuditLog 和类 AuditDetail 分别放置在两个文件中,由于外键定义的刚需,我们必须在 audit_detail.py 中全局导入 AuditLog

from .audit_log import AuditLog

class AuditDetail(models.Model):
    audit_log = models.ForeignKey(AuditLog, on_delete=models.CASCADE, related_name="_details")

如果我们在 audit_log.py 中全局导入 AuditDetail,就会触发 循环导入 的问题。

最直观的办法是在属性方法内部导入:

class AuditLog(models.Model):
    @property
    def details(self):
        from .audit_detail import AuditDetail
        
        qs: QuerySet[AuditDetail] = self._details.all()
        # 同样可以使用字符串注解类型
        # qs: QuerySet["AuditDetail"] = self._details.all()
        return qs

但是显然,这样的代码不太优雅。

此时可以使用 TYPE_CHECKING 常量可以在类型检查阶段导入类,而在运行时忽略这些导入,从而避免循环导入问题。

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from .audit_detail import AuditDetail
    
class AuditLog(models.Model):
    @property
    def details(self) -> QuerySet["AuditDetail"]:
        return self._details.all()
    
    @property
    def first_detail(self) -> "AuditDetail":
        return self.details.first()

此解决方案相当于将 AuditDetail 仅作为类型导入,它在实际运行时是不存在的,所以对应使用的地方必须使用 字符串注解类型

0

评论区