Reputation: 9909
What type hint to use for a function which returns a queryset like the one below?
def _get_cars_for_validation(filter_: dict) -> QuerySet:
return (
Car.objects.filter(**filter_)
.values("id", "brand", "engine")
.order_by("id")
)
mypy
returns an error
Incompatible return value type (got "ValuesQuerySet[Car, TypedDict({'id': int, 'brand': str, 'engine': str})]", expected "QuerySet[Any]")
I would use ValuesQuerySet
but it was removed in Django 1.9. ValuesQuerySet
reported by mypy
comes from 3rd party lib django-stubs
(and I am unable to import it; is it actually possible?).
Upvotes: 10
Views: 5424
Reputation: 1531
You can also cast to QuerySet
:
from typing import cast
from django.db.models import QuerySet
return (
cast(QuerySet, Car.objects.filter(**filter_))
.values("id", "brand", "engine")
.order_by("id")
)
Upvotes: 2
Reputation: 1622
I had exactly the same problem, and I found a solution in a GitHub issue:
import typing
if typing.TYPE_CHECKING:
from django.db.models.query import ValuesQuerySet
def _get_cars_for_validation(filter_: dict) -> 'ValuesQuerySet[Car, int]':
return (
Car.objects.filter(**filter_)
.values("id", "brand", "engine")
.order_by("id")
)
The if typing.TYPE_CHECKING
prevents the ImportError
when you run the program, because the nonexistent ValuesQuerySet
is only imported during the mypy check.
Also note that the annotation has to be a string: 'ValuesQuerySet[Car, int]'
.
The second argument to 'ValuesQuerySet[Car, int]'
is a mystery to me; the OP of the issue used int
"and it worked", in my case I tried a few other types, and all of them worked too; you may just as well use Any
, I suppose.
You can use reveal_type()
to inspect the type of the variable yourself.
Upvotes: 7