Je travaille sur un projet Django. Comme il s'agit d'un nouveau projet, je veux qu'il soit entièrement annoté avec les annotations de type python 3.6+). Je ' m essayant d'annoter des modèles, mais j'ai du mal à trouver une bonne méthode pour cela.
Prenons l'exemple de IntegerField
. Je vois deux choix pour l'annoter:
# number 1
int_field: int = models.IntegerField()
# number 2
int_field: models.IntegerField = models.IntegerField()
Le numéro 1 échoue dans mypy:
Incompatible types in assignment (expression has type "IntegerField[<nothing>, <nothing>]", variable has type "int")
Le numéro 2 est OK pour mypy, mais les IDE comme PyCharm ne sont pas en mesure de le résoudre et se plaignent souvent des mauvais types utilisés.
Existe-t-il des meilleures pratiques pour annoter correctement les modèles, qui satisferont mypy et IDE?
Les modèles de Django (et d'autres composants) sont difficiles à annoter car il y a beaucoup de magie derrière eux, la bonne nouvelle est qu'un groupe de développeurs sympas ont déjà fait le travail acharné pour nous.
Django-stubs fournit un ensemble de stubs et de plugins mypy qui fournissent des types statiques et des inférences de types pour Django.
Par exemple, avoir le modèle suivant:
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 se plaindrait en disant:
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)
Pour le réparer, il suffit d'installer le package
pip install Django-stubs
et créez un setup.cfg
fichier avec les éléments suivants:
[mypy]
plugins =
mypy_Django_plugin.main
strict_optional = True
[mypy.plugins.Django-stubs]
Django_settings_module = demo.settings
(N'oubliez pas de mettre à jour Django_settings_module
selon votre module de paramètres)
Une fois cela fait, mypy pourra déduire et vérifier les annotations pour les modèles Django (et autres composants).
demo$ mypy .
Success: no issues found in 5 source files
Voici un exemple d'utilisation dans une petite vue:
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()})
Encore une fois, mypy est satisfait des annotations fournies:
demo$ mypy .
Success: no issues found in 7 source files
Sur la même note, un package pour Django Rest Framework est également disponible: djangorestframework-stubs .