考虑以下情况:
class AuditLog(models.Model):
pass
class AuditDetail(models.Model):
audit_log = models.ForeignKey(AuditLog, on_delete=models.CASCADE, related_name="_details")
log = AuditLog.objects.first()
detail = AuditDetail.objects.first()
AuditDetail 类上直接定义了 audit_log 字段,所以 detail.audit_log 可以直接获得 类型提示。
对应的,log._details 是框架隐式添加的,它默认是 Any 类型。
为了给 log._details 加上类型提示,我们可以给 AuditLog 类直接添加一个属性方法:
class AuditLog(models.Model):
@property
def details(self):
return self._details.all()
但是这样获得的 log.details 仍然是无类型提示的(它的实际类型是 QuerySet[AuditDetail])。
我们可以显式标注返回值类型:
class AuditLog(models.Model):
@property
def details(self) -> QuerySet[AuditDetail]:
return self._details.all()
这时存在一个问题:AuditDetail 类是在 AuditLog 类后面定义的,AuditDetail 类中需要引用 AuditLog 类作为外键关联模型。
上述代码实际上使用了未定义的变量,这种困境叫做 前向引用问题,即两个类互相引用,前一个类不能直接引用后一个类。
解决办法:
1、使用 字符串注解(Python 3.7+)
从 Python 3.7 开始,可以直接用字符串来表示类型:
class AuditLog(models.Model):
@property
def details(self) -> QuerySet["AuditDetail"]:
return self._details.all()
2、使用 __future__ 模块(Python 3.6)
from __future__ import annotations
class AuditLog(models.Model):
@property
def details(self) -> QuerySet[AuditDetail]:
return self._details.all()
注意:from __future__ import annotations 必须放在文件的第一行。
3、使用 Type 和 Union(≤ Python 3.5)
略,还是升级 Python 版本吧。
评论区