web-dev-qa-db-fra.com

Comment utiliser les indicateurs de type Python avec Django QuerySet?

Est-il possible de spécifier le type d'enregistrements dans Django QuerySet avec des indicateurs de type Python? Quelque chose comme QuerySet[SomeModel]?

Par exemple, nous avons le modèle:

class SomeModel(models.Model):
    smth = models.IntegerField()

Et nous voulons transmettre QuerySet de ce modèle en tant que paramètre in func:

def somefunc(rows: QuerySet):
    pass

Mais comment spécifier le type d’enregistrements dans QuerySet, comme avec List[SomeModel]:

def somefunc(rows: List[SomeModel]):
    pass

mais avec QuerySet?

Une solution peut utiliser la classe de frappe Union.

from typing import Union, List
from Django.db.models import QuerySet
from my_app.models import MyModel

def somefunc(row: Union[QuerySet, List[MyModel]]):
    pass

Désormais, lorsque vous coupez l'argument row, il sait que le type renvoyé est une autre liste de MyModel ou une instance de MyModel, tout en indiquant que les méthodes de la classe QuerySet sont également disponibles sur l'argument row.

20
A. J. Parr

Je cherche une solution à cela aussi. La liste Django Developers contient un thread dans lequel ils discutent de la manière de mettre en œuvre une telle fonctionnalité.

Ils développent actuellement une extension Django à mypy , mais il semble que nous ayons peut-être de la chance pour notre demande spécifique. Dans leur feuille de route sous le titre "Probablement jamais":

Les ensembles de requêtes peuvent avoir un support partiel, mais des arguments complexes (comme Ceux pour les requêtes de filtrage et d'obtention de requêtes) ou les objets Q et F vont au-delà de. possibilités expressives de mypy comme il est maintenant.

En déclarant cela, nous devrons simplement utiliser la règle QuerySet jusqu'à ce que les conditions s'améliorent.

1
Bobort

J'ai créé cette classe d'assistance pour obtenir un indice de type générique:

from Django.db.models import QuerySet
from typing import Iterator, Union, TypeVar, Generic

T = TypeVar("T")

class ModelType(Generic[T]):
    def __iter__(self) -> Iterator[Union[T, QuerySet]]:
        pass

Ensuite, utilisez-le comme ceci:

def somefunc(row: ModelType[SomeModel]):
    pass

Cela réduit le bruit chaque fois que j'utilise ce type et le rend utilisable entre les modèles (comme ModelType[DifferentModel]).

0
Or Duan