Skip to content

Subclass AioinjectMiddleware

Since Django doesn't allow you to parametrize middleware (e.g. like starlette does) we need to subclass AioinjectMiddleware:

app/di.py
import functools
import random

from aioinject import Scoped, SyncContainer
from aioinject.ext.django import SyncAioinjectMiddleware


@functools.cache
def create_container() -> SyncContainer:
    container = SyncContainer()
    container.register(
        Scoped(lambda: random.randint(1, 1000), interface=int),  # noqa: S311
    )
    return container


class DIMiddleware(SyncAioinjectMiddleware):
    container = create_container()
alternatively you can declare a property if needed:
class DIMiddleware(SyncAioinjectMiddleware):
    @property
    def container(self) -> SyncContainer:
        return create_container()

Add middleware to your settings.MIDDLEWARE

app/settings.py
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "app.di.DIMiddleware",
]

Mark your view with @inject

views.py
from django.http import HttpRequest, HttpResponse

from aioinject import Injected
from aioinject.ext.django import inject


@inject
def root_view(
    _: HttpRequest,
    dependency: Injected[int],
) -> HttpResponse:
    return HttpResponse(content=f"{dependency}")

Warning

Since django and rest_framework pass request as a positional argument your request parameter should always be declared first.

Integration with Rest Framework

@inject decorator should work with any function/method that accepts django.http.HttpRequest or rest_framework.request.Request:

from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet

from aioinject import Injected
from aioinject.ext.django import inject


class ViewExample(APIView):
    @inject
    def get(self, _: Request, number: Injected[int]) -> Response:
        return Response({"value": number})


class ViewSetExample(ViewSet):
    @inject
    def retrieve(
        self,
        _: Request,
        pk: int,
        number: Injected[int],
    ) -> Response:
        return Response({"id": pk, "value": number})