-
Notifications
You must be signed in to change notification settings - Fork 414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async middleware #639
Comments
I was able to achieve this by creating custom middleware (based on the official one), it is both sync and async capable and works just fine for my use cases: Currently running on Django 5.0.4 and AuditLog 3.0.0 import contextlib
import time
from contextvars import ContextVar
from functools import partial
from asgiref.sync import iscoroutinefunction
from auditlog.models import LogEntry
from django.contrib.auth import get_user_model
from django.db.models.signals import pre_save
from django.utils.decorators import sync_and_async_middleware
duid = ContextVar('duid')
remote_address = ContextVar('remote_address')
UserModel = get_user_model()
@contextlib.contextmanager
def set_actor(actor, remote_addr=None):
signal_duid = ('set_actor', time.time())
duid.set(signal_duid)
remote_address.set(remote_addr)
set_actor = partial(_set_actor, user=actor, signal_duid=signal_duid)
pre_save.connect(
set_actor,
sender=LogEntry,
dispatch_uid=signal_duid,
weak=False,
)
try:
yield
finally:
pre_save.disconnect(sender=LogEntry, dispatch_uid=signal_duid)
def _set_actor(user, sender, instance, signal_duid, **kwargs):
try:
ctx_duid = duid.get()
ctx_remote_address = remote_address.get()
except LookupError:
return
if signal_duid != ctx_duid:
return
if sender == LogEntry and isinstance(user, UserModel) and instance.actor is None:
instance.actor = user
instance.remote_addr = ctx_remote_address
@sync_and_async_middleware
def AuditlogMiddleware(get_response):
if iscoroutinefunction(get_response):
async def middleware(request):
if hasattr(request, 'auser'):
user = await request.auser()
if user.is_authenticated:
context = set_actor(actor=user, remote_addr=request.META['REMOTE_ADDR'])
else:
context = contextlib.nullcontext()
else:
context = contextlib.nullcontext()
with context:
return await get_response(request)
else:
def middleware(request):
if hasattr(request, 'user') and request.user.is_authenticated:
context = set_actor(actor=request.user, remote_addr=request.META['REMOTE_ADDR'])
else:
context = contextlib.nullcontext()
with context:
return get_response(request)
return middleware |
In addition to my last post, I am also using this sync and async middleware to get the 'REMOTE_ADDR' meta: from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware
@sync_and_async_middleware
def RemoteAddressMiddleware(get_response):
if iscoroutinefunction(get_response):
async def middleware(request):
remote_addr = (
request.META.get('REMOTE_ADDR', '')
or request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0].strip()
)
if '.' in remote_addr and ':' in remote_addr:
remote_addr = remote_addr.split(':')[0].strip()
elif '[' in remote_addr:
remote_addr = remote_addr[1:].split(']')[0].strip()
request.META['REMOTE_ADDR'] = remote_addr
return await get_response(request)
else:
def middleware(request):
remote_addr = (
request.META.get('REMOTE_ADDR', '')
or request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0].strip()
)
if '.' in remote_addr and ':' in remote_addr:
remote_addr = remote_addr.split(':')[0].strip()
elif '[' in remote_addr:
remote_addr = remote_addr[1:].split(']')[0].strip()
request.META['REMOTE_ADDR'] = remote_addr
return get_response(request)
return middleware This should be relatively at the top of your MIDDLEWARE list, example: MIDDLEWARE = [
'config.middleware.RemoteAddressMiddleware', # <-- Custom sync/async REMOTE_ADDR middleware
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'config.middleware.RemoteUserMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'config.middleware.AuditlogMiddleware', # <-- Custom sync/async AuditLog middleware
] |
Please take this into account, as it is blocking the whole async signal functionality for all requests. |
Hi,
Are there any plans to implement async in the current middleware? At the moment using the middleware forces the entire request pipeline to be sync as the middleware doesn't support a async.
Cheers,
Steve.
The text was updated successfully, but these errors were encountered: