如何让 mypy 识别 login_required 装饰器?

etn*_*n03 4 python django mypy

我有以下 Django 视图:

@login_required
def view(request: HttpRequest) -> HttpResponse:
    if not request.user.some_attribute:
        return redirect("somewhere")
    return render(request, "template_name")
Run Code Online (Sandbox Code Playgroud)

以及一个User具有属性 的自定义模型some_attribute

我用mypy这个来强制类型检查mypy.ini

[mypy]
ignore_missing_imports = True
plugins = mypy_django_plugin.main

[mypy.plugins.django-stubs]
django_settings_module = [PROJECT NAME].settings
Run Code Online (Sandbox Code Playgroud)

但是,mypy出现以下错误:

Item "AnonymousUser" of "Union[User, AnonymousUser]" has no attribute "some_attribute"
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为匿名用户不会有该属性,但我有一个login_required装饰器,使得AnonymousUsers 不可能(它将是 a User)。

我如何告诉mypy忽略这一点,而不使用# type: ignore

Gwy*_*idD 5

您还可以子类化HttpRequest并显式设置user子类上的字段,以将类型显式定义为User而不是默认的联合对,如下所示:

from django.http import HttpRequest
from my_user_app.models import MyUser

class AuthenticatedHttpRequest(HttpRequest):
    user: MyUser
Run Code Online (Sandbox Code Playgroud)

然后,每次您想要使用login_required装饰器时,请将参数的类型提示设置request为您的子类(在本例中为AuthenticatedHttpRequest),如下所示:

@login_required
def view(request: AuthenticatedHttpRequest) -> HttpResponse:
    if not request.user.some_attribute:
        return redirect("somewhere")
    return render(request, "template_name")
Run Code Online (Sandbox Code Playgroud)

django-stubs此方法在自述文件中被指定为推荐方法,显然您正在使用该方法来获取mypy.