How to annotate Django view's methods?
Question:
I’d like to use Python type hints in my Django project. What’s the proper way to annotate get
/post
methods of a simple class-based view in Django?
I’ve searched the Django code itself but it doesn’t seem to contain any type hints.
Answers:
[UPDATE 15/12/2022]: Well I have forgotten this answer, but it seems that you don’t need a project that is not maintained for the last 6 years if you use Python 3.6+.
Just use typing (if needed) and type hints as normal.
Example:
def get(self, request: HttpRequest, question_id: typing.Optional[str] = None) -> HttpResponse:
# code here
There exists this repository which may interest you: https://github.com/machinalis/mypy-django
which will allow you to use annotations like so:
def get(self, request: HttpRequest, question_id: str) -> HttpResponse:
If using function-based views, and if you don’t want or need mypy-django, you can do:
from django.http import HttpRequest, HttpResponse, JsonResponse
def some_fbv(request: HttpRequest) -> HttpResponse:
....
return foo
def some_json_producing_fbv(request: HttpRequest) -> JsonResponse:
...
return foo
Django stubs is well maintained package, https://github.com/typeddjango/django-stubs.
import typing as t
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View
from django.http import HttpRequest, HttpResponse, JsonResponse,
HttpResponseRedirect
from .forms import MyForm
# type alias when response is one of these types
RedirectOrResponse = t.Union[HttpResponseRedirect, HttpResponse]
class MyFormView(View):
form_class = MyForm
initial = {'key': 'value'}
template_name = 'form_template.html'
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request: HttpRequest, *args: tuple[Any],
**kwargs: dict[str, t.Union[int, str]]) -> RedirectOrResponse:
form: MyForm = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
return render(request, self.template_name, {'form': form})
HttpRequest
maps to request variable in the function or method.
HttpResponse, JsonResponse, StreamingResponse, Redirect
will be value returned by the view function/method.
*args, **kwargs
is easy and tricky, since it can be of any tuple of values or dictionary of values. *args: Any
or *args: tuple[Any]
(you can also use specific types if you know about it). The same applies to **kwargs
.
- Whenever the class is passed or returned, use
type[cls]
.
More Examples: https://github.com/typeddjango/django-stubs/tree/master/tests
I’d like to use Python type hints in my Django project. What’s the proper way to annotate get
/post
methods of a simple class-based view in Django?
I’ve searched the Django code itself but it doesn’t seem to contain any type hints.
[UPDATE 15/12/2022]: Well I have forgotten this answer, but it seems that you don’t need a project that is not maintained for the last 6 years if you use Python 3.6+.
Just use typing (if needed) and type hints as normal.
Example:
def get(self, request: HttpRequest, question_id: typing.Optional[str] = None) -> HttpResponse:
# code here
There exists this repository which may interest you: https://github.com/machinalis/mypy-django
which will allow you to use annotations like so:
def get(self, request: HttpRequest, question_id: str) -> HttpResponse:
If using function-based views, and if you don’t want or need mypy-django, you can do:
from django.http import HttpRequest, HttpResponse, JsonResponse
def some_fbv(request: HttpRequest) -> HttpResponse:
....
return foo
def some_json_producing_fbv(request: HttpRequest) -> JsonResponse:
...
return foo
Django stubs is well maintained package, https://github.com/typeddjango/django-stubs.
import typing as t
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View
from django.http import HttpRequest, HttpResponse, JsonResponse,
HttpResponseRedirect
from .forms import MyForm
# type alias when response is one of these types
RedirectOrResponse = t.Union[HttpResponseRedirect, HttpResponse]
class MyFormView(View):
form_class = MyForm
initial = {'key': 'value'}
template_name = 'form_template.html'
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request: HttpRequest, *args: tuple[Any],
**kwargs: dict[str, t.Union[int, str]]) -> RedirectOrResponse:
form: MyForm = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
return render(request, self.template_name, {'form': form})
HttpRequest
maps to request variable in the function or method.HttpResponse, JsonResponse, StreamingResponse, Redirect
will be value returned by the view function/method.*args, **kwargs
is easy and tricky, since it can be of any tuple of values or dictionary of values.*args: Any
or*args: tuple[Any]
(you can also use specific types if you know about it). The same applies to**kwargs
.- Whenever the class is passed or returned, use
type[cls]
.
More Examples: https://github.com/typeddjango/django-stubs/tree/master/tests