【问题标题】:Type annotations for Django modelsDjango 模型的类型注释
【发布时间】:2019-11-25 12:34:49
【问题描述】:

我正在开发一个 Django 项目。由于这是一个新项目,我想用 python 3.6+ 类型注释对其进行完全注释。我正在尝试注释模型,但我很难找到一个好的方法。

我们以IntegerField 为例。我看到了两种注释它的选择:

# number 1
int_field: int = models.IntegerField()

# number 2
int_field: models.IntegerField = models.IntegerField()

mypy 中的数字 1 失败:

Incompatible types in assignment (expression has type "IntegerField[<nothing>, <nothing>]", variable has type "int")

2 号对于 mypy 来说是可以的,但作为 PyCharm 的 IDE 无法解决它,并且经常抱怨使用了错误的类型。

是否有任何最佳实践来正确注释模型,这将满足 mypy 和 IDE 的要求?

【问题讨论】:

  • 由于您似乎在令人满意的工具上投入了大量时间,因此您可能会惊讶地发现,您所做的并不是 不是 设计的类型注释:静态打字。
  • 你不是在寻找类似mypy-django的东西吗?
  • 看起来 mypy-django 不提供模型的类型注释:github.com/machinalis/mypy-django-example/blob/master/polls/…
  • @KlausD。 - 我不确定我是否明白你在说什么,你能详细说明一下吗?
  • @aaron:不,因为这绝对是错误的。问题是 Django 模型是一个非常不同的野兽。类包含字段,实例包含具体值。类型随上下文变化,实例没有IntegerField,但如果您使用Union,那么所有访问该字段的代码都必须考虑这种可能性。

标签: python django type-annotation


【解决方案1】:

Django 模型(和其他组件)很难注释,因为它们背后有很多魔法,好消息是一群很酷的开发人员已经为我们完成了艰苦的工作。

django-stubs 提供了一组存根和 mypy 插件,为 Django 提供静态类型和类型推断。

例如,具有以下模型:

from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class Post(models.Model):
    title = models.CharField(max_length=255)
    pubdate = models.DateTimeField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)

mypy 会抱怨说:

demo$ mypy .
demo/models.py:9: error: Need type annotation for 'title'
demo/models.py:10: error: Need type annotation for 'pubdate'
demo/models.py:11: error: Need type annotation for 'author'
Found 3 errors in 1 file (checked 5 source files)

要修复它,安装包就足够了

pip install django-stubs

并使用以下内容创建setup.cfg 文件:

[mypy]
plugins =
    mypy_django_plugin.main

strict_optional = True

[mypy.plugins.django-stubs]
django_settings_module = demo.settings

(别忘了根据你的设置模块更新django_settings_module

完成此操作后,mypy 将能够推断和检查 Django 模型(和其他组件)的注释。

demo$ mypy .
Success: no issues found in 5 source files

这是一个小视图的用法示例:

from django.db.models.query import QuerySet
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render

from demo.models import Post

def _get_posts() -> 'QuerySet[Post]':
    return Post.objects.all()

def posts(request: HttpRequest, template: str='posts.html') -> HttpResponse:
    return render(request, template, {'posts': _get_posts()})

mypy 再次对提供的注释感到满意:

demo$ mypy .
Success: no issues found in 7 source files

同样,Django Rest Framework 的包也可用:djangorestframework-stubs

【讨论】:

  • 我确实找到了这个,但我用错了。感谢您提供帮助我前进的详细答案。
  • 看起来该插件也尝试执行 Django 项目本身,所以如果它无法运行,例如:它依赖于特定环境等。
猜你喜欢
  • 2011-07-04
  • 2014-11-13
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
相关资源
最近更新 更多