考虑以下情况:
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 版本吧。
评论区