Skip to content
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

Use sync/async pattern for middleware since Django 3.1 #1209

Merged
merged 3 commits into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Unreleased
- Made ``bulk_update_with_history()`` return the number of model rows updated (gh-1206)
- Fixed ``HistoryRequestMiddleware`` not cleaning up after itself (i.e. deleting
``HistoricalRecords.context.request``) under some circumstances (gh-1188)
- Made ``HistoryRequestMiddleware`` async-capable (gh-1209)

3.3.0 (2023-03-08)
------------------
Expand Down
43 changes: 30 additions & 13 deletions simple_history/middleware.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
from contextlib import contextmanager

from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware

from .models import HistoricalRecords


class HistoryRequestMiddleware:
@contextmanager
def _context_manager(request):
HistoricalRecords.context.request = request

try:
yield None
finally:
del HistoricalRecords.context.request


@sync_and_async_middleware
def HistoryRequestMiddleware(get_response):
"""Expose request to HistoricalRecords.

This middleware sets request as a local context/thread variable, making it
available to the model-level utilities to allow tracking of the authenticated user
making a change.
"""

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

def __call__(self, request):
HistoricalRecords.context.request = request
try:
response = self.get_response(request)
except Exception as e:
raise e
finally:
del HistoricalRecords.context.request
return response
if iscoroutinefunction(get_response):

async def middleware(request):

Check warning on line 30 in simple_history/middleware.py

View check run for this annotation

Codecov / codecov/patch

simple_history/middleware.py#L30

Added line #L30 was not covered by tests
with _context_manager(request):
return await get_response(request)

Check warning on line 32 in simple_history/middleware.py

View check run for this annotation

Codecov / codecov/patch

simple_history/middleware.py#L32

Added line #L32 was not covered by tests

else:

def middleware(request):
with _context_manager(request):
return get_response(request)

return middleware