Is it possible to specify type of records in Django QuerySet with Python type hints? Something like QuerySet[SomeModel]
?
For example, we have model:
One solution may be using Union typing class.
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
Now when you slice the row
argument it will know that the returned type is either another list of MyModel or an instance of MyModel, whilst also hinting that the methods of the QuerySet
class are available on the row
argument too.
There's a special package called django-stubs
(the name follows PEP561) to type your django
code.
That's how it works:
# 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')
Output:
» 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'
And with models and 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,
)
Output:
reveal_type(published_posts().first())
# => Union[server.apps.main.models.BlogPost*, None]
django
: https://github.com/typeddjango/django-stubsdrf
: https://github.com/typeddjango/djangorestframework-stubsYou actually can do what you want if you import the annotations module:
from __future__ import annotations
from django.db import models
from django.db.models.query import QuerySet
class MyModel(models.Model):
pass
def my_function() -> QuerySet[MyModel]:
return MyModel.objects.all()
Neither MyPy nor the Python interpreter will complain or raise exceptions on this (tested on python 3.7). MyPy will probably be unable to type-check it, but if all you want is to document your return type, this should be good enough.