在Django中输入泛型实用程序的提示

pod7payv  于 2023-01-18  发布在  Go
关注(0)|答案(2)|浏览(123)
def get_or_create_object(self, model : ?(what will be the type?), data: dict) -> ? (what will be the return type):
        try:
            obj, _ = model.objects.get_or_create(**data)
        except model.MultipleObjectsReturned:
            obj = model.objects.filter(**data).first()
        return obj

get_or_create_object(ModelName, data)

这里的类型提示是什么- as函数将动态获取Model示例。

vdgimpew

vdgimpew1#

既然你希望你的函数在你传递给它的特定模型类方面是通用的,那么@SUTerliakov在他的评论中说了解决方案。你需要定义一个typing.TypeVar,并且理想地给予它一个Model的上限,以缩小它可以表示的类型。有关细节,请参见相关的PEP 484部分。
以下是您的操作方法:

from typing import Any, TypeVar, cast

from django.db.models import Model

M = TypeVar("M", bound=Model)

def get_or_create_object(model: type[M], data: dict[str, Any]) -> M:
    try:
        obj, _ = model.objects.get_or_create(**data)
    except model.MultipleObjectsReturned:
        obj = cast(M, model.objects.filter(**data).first())
    return obj

注意,我们需要使用typing.cast,因为QuerySet.first方法可以返回模型**或None**的示例,而类型检查器不够聪明,无法知道在这种特定情况下它永远不会返回None(由于之前捕获的MultipleObjectsReturned异常),因此我们需要让类型检查器清楚地知道该值确实是我们模型的示例。
为了证明:

class SpecificModel(Model):
    def foo(self) -> int:
        return 1

instance = get_or_create_object(SpecificModel, {})
reveal_type(instance)
reveal_type(instance.foo())

在此基础上运行mypy,得到以下输出:

note: Revealed type is "SpecificModel"
note: Revealed type is "builtins.int"

因此,类型检查器正确地推断出函数返回的示例的类型。
顺便说一句,如果你愿意的话,你可以扩展data的类型,因为它可以是任何Mapping,而不一定是字典,为此你只需要做from collections.abc import Mapping,然后用data: Mapping[str, Any]来注解它。

fbcarpbf

fbcarpbf2#

您可以使用models.ModelType[models.Model]所有Django模型都继承自models.Model,并且发送给函数的模型是相同的类型,当然,如果您想说它是一个类并且是这个类的子集,您可以使用Type[models.Model]

from typing import Type
from django.db import models

def get_or_create_object(model: Type[models.Model], data: dict) -> models.Model:
    try:
        obj, _ = model.objects.get_or_create(**data)
    except model.MultipleObjectsReturned:
        obj = model.objects.filter(**data).first()
    return obj

注意:get_or_create存在于Django内置中:

exp = Example.objects.get_or_create(**data)

相关问题