Current User¶
The current_user subsystem provides async-safe, request-scoped user
resolution using Python’s contextvars.ContextVar.
Motivation¶
The standard DRF pattern for accessing the current user in nested components
(serializers, signals, model methods) involves threading request or
request.user through each function call. This creates coupling between
the request object and business logic, complicates testing, and fails silently
in async contexts when thread-local storage is used instead.
drf-commons uses a ContextVar — a value scoped to the current execution
context (thread in WSGI, coroutine in ASGI) — set once per request by
CurrentUserMiddleware and readable anywhere in the call stack without
explicit propagation.
Public API¶
from drf_commons.current_user import (
get_current_user,
get_current_authenticated_user,
)
get_current_user¶
Returns the user currently stored in the context variable.
user = get_current_user()
Returns:
The authenticated
Userinstance if the request user is authenticatedAnonymousUserif the request user is not authenticatedNoneif called outside a request context (e.g., management commands, Celery tasks)
get_current_authenticated_user¶
Returns the authenticated user. Raises if the user is not authenticated or if called outside a request context.
user = get_current_authenticated_user()
Use this in contexts where an authenticated user is required:
UserActionMixin.save()— populatescreated_by/updated_byCurrentUserField.default— populates FK on model creation
Internal API¶
The following functions are internal to drf-commons and should not be called directly in application code:
from drf_commons.current_user.utils import (
_set_current_user,
_reset_current_user,
_clear_current_user,
)
_set_current_user(user)— Sets the context variable, returns a reset token_reset_current_user(token)— Resets the context variable to its previous state_clear_current_user()— Sets the context variable toNone
The token-based reset pattern is essential for correctness in async contexts where coroutines may share a context chain. Using tokens preserves the previous state rather than clearing it unconditionally.
Usage Outside Request Context¶
In management commands, Celery tasks, or other non-request contexts, the context variable is not set by middleware. You can manually set it when necessary:
from django.contrib.auth import get_user_model
from drf_commons.current_user.utils import _set_current_user, _reset_current_user
User = get_user_model()
def run_as_user(user_id: int, fn: callable):
"""Execute fn() with the context user set to the given user."""
user = User.objects.get(pk=user_id)
token = _set_current_user(user)
try:
return fn()
finally:
_reset_current_user(token)
This pattern is useful in Celery tasks that perform model modifications and
need UserActionMixin audit trail population.
Testing with Context User¶
In tests, set the context user directly:
from drf_commons.current_user.utils import _set_current_user, _reset_current_user
class ArticleCreateTestCase(TestCase):
def test_creates_with_correct_author(self):
user = UserFactory()
token = _set_current_user(user)
try:
article = Article.objects.create(title="Test", content="Body")
assert article.created_by == user
finally:
_reset_current_user(token)
Or use the provided test utilities and factories from
drf_commons.common_tests, which handle this automatically.