web-dev-qa-db-fra.com

Tapez des annotations pour les modèles Django

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?

8
Djent

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 .

8
bug