¿Es posible especificar el tipo de registros en Django QuerySet con sugerencias de tipo Python? ¿Algo así como QuerySet[SomeModel] ?
Por ejemplo, tenemos el modelo:
class SomeModel(models.Model): smth = models.IntegerField()Y queremos pasar QuerySet de ese modelo como param en func:
def somefunc(rows: QuerySet): pass Pero cómo especificar el tipo de registros en QuerySet, como con List[SomeModel] :
def somefunc(rows: List[SomeModel]): passpero con QuerySet?
Una solución puede ser usar la clase de escritura 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 Ahora, cuando corte el argumento de la row , sabrá que el tipo devuelto es otra lista de MyModel o una instancia de MyModel, al mismo tiempo que indica que los métodos de la clase QuerySet están disponibles en el argumento de la row .
Hay un paquete especial llamado django-stubs (el nombre sigue a PEP561 ) para escribir tu código django .
Asi es como funciona:
# server/apps/main/views.py from django.http import HttpRequest, HttpResponse from django.shortcuts import render def index(request: HttpRequest) -> HttpResponse: reveal_type(request.is_ajax) reveal_type(request.user) return render(request, 'main/index.html')Producción:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server server/apps/main/views.py:14: note: Revealed type is 'def () -> builtins.bool' server/apps/main/views.py:15: note: Revealed type is 'django.contrib.auth.models.User' Y con modelos y QuerySet s:
# server/apps/main/logic/repo.py from django.db.models.query import QuerySet from server.apps.main.models import BlogPost def published_posts() -> 'QuerySet[BlogPost]': # works fine! return BlogPost.objects.filter( is_published=True, )Producción:
reveal_type(published_posts().first()) # => Union[server.apps.main.models.BlogPost*, None]django : https://github.com/typeddjango/django-stubsdrf : https://github.com/typeddjango/djangorestframework-stubsHice esta clase de ayuda para obtener una sugerencia de tipo genérico:
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]]: passEntonces úsalo así:
def somefunc(row: ModelType[SomeModel]): pass Esto reduce el ruido cada vez que uso este tipo y lo hace utilizable entre modelos (como ModelType[DifferentModel] ).