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.

Asked By: planetp

||

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:
Answered By: John Moutafis

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
Answered By: shacker

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

Answered By: Kracekumar