How can I make Django signals request-aware for audit logging

I am building an audit trail system in Django where I need access to the current HTTP request inside model signals (pre_save, post_save, pre_delete, post_delete).

The goal is to make signals “request-aware” so I can log:

  • authenticated user (request.user)

  • IP address

  • and other request metadata

without explicitly passing the request through every service layer call.

Since Django signals do not natively provide the request object, I tried solving this using contextvars.ContextVar. Below are the codes

# request_context.py
from contextvars import ContextVar

current_request = ContextVar("current_request", default=None)


def get_current_request():
    """Retrieve the current request from context."""
    return current_request.get()
# middleware.py
from core.request_context import current_request


class CurrentRequestMiddleware:
    """
    Stores the current HTTP request in a ContextVar
    so it can be accessed globally (e.g. inside signals).
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        print("SETTING REQUEST:", request)

        token = current_request.set(request)

        try:
            response = self.get_response(request)
        finally:
            current_request.reset(token)

        return response

And below is where i execute it in signals

from core.request_context import get_current_request

request = get_current_request()

if request:
    print(request.__dict__)
else:
    print("Request is None")

Expected behavior

I expected that since:

  • middleware executes successfully
  • request is set using ContextVar.set()
  • signals are triggered during normal request lifecycle (Django admin / API requests)

then get_current_request() inside signals should return the active HttpRequest. But ContextVar.get() returns None inside signal handlers. So now my questions is?

What is the correct way to make Django signals “request-aware” so that I can reliably access the current HttpRequest inside signals for audit logging? or better still, What is the recommended production-safe pattern for achieving request-aware audit logging in Django

I am aware that using Django signals for audit logging is generally considered an anti-pattern and not recommended for complex systems. However, in this project I am constrained by the following requirements:

  • I cannot use external dependencies or third-party audit libraries.
  • I need a built-in Django solution.
  • I must log all model-level actions (create, update, delete) to an audit table.
  • The system should capture request context (user, IP) whenever available. Audit logging must be automatic and not require explicit calls across the codebase.

The goal is to ensure that all Django ORM-driven operations on models are tracked centrally.

Вернуться на верх