Skip to content

Commit

Permalink
Update middlewares.py
Browse files Browse the repository at this point in the history
Add

Update CI.yml

Update middlewares.py

Update middlewares.py

Update CI.yml

Revert "Update CI.yml"

This reverts commit dc01841.
  • Loading branch information
baseplate-admin committed Dec 10, 2024
1 parent 2c13711 commit 398accd
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 129 deletions.
8 changes: 1 addition & 7 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.10', '3.11', '3.12', '3.13']
django-version: ['3.2', '4.0', '4.1', '4.2', '5.0', '5.1']

exclude:
# Python 3.9
- python-version: '3.9'
django-version: '5.0'
- python-version: '3.9'
django-version: '5.1'

# Python 3.13
- python-version: '3.13'
django-version: '3.2'
Expand Down
42 changes: 33 additions & 9 deletions ninja_put_patch_file_upload_middleware/middlewares.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,68 @@
from collections.abc import Callable
from typing import Any, Union
from collections.abc import Awaitable, Callable
from typing import Any, TypeAlias

from asgiref.sync import iscoroutinefunction, sync_to_async
from django.http import HttpRequest, HttpResponse
from django.utils.decorators import sync_and_async_middleware

TARGET_METHODS = ("PUT", "PATCH")
# Type aliases for improved readability and type clarity
ResponseType: TypeAlias = HttpResponse | Any
RequestHandler: TypeAlias = Callable[[HttpRequest], ResponseType]
AsyncRequestHandler: TypeAlias = Callable[[HttpRequest], Awaitable[ResponseType]]

TARGET_METHODS = {"PUT", "PATCH"}


@sync_and_async_middleware
def process_put_patch(
get_response: Union[
Callable[[HttpRequest], HttpResponse], Callable[[HttpRequest], Any]
],
) -> Union[Callable[[HttpRequest], Any], Callable[[HttpRequest], HttpResponse]]:
async def async_middleware(request: HttpRequest) -> Union[HttpResponse, Any]:
get_response: RequestHandler | AsyncRequestHandler,
) -> RequestHandler | AsyncRequestHandler:
"""
Middleware to handle PUT and PATCH requests when content type is not JSON.
Converts the request method to POST temporarily to enable file/post data parsing.
Args:
get_response: The next middleware or view handler in the request processing chain.
Returns:
An async or sync middleware function based on the input handler type.
"""

async def async_middleware(request: HttpRequest) -> ResponseType:
if (
request.method in TARGET_METHODS
and request.content_type != "application/json"
):
initial_method = request.method
request.method = "POST"
request.META["REQUEST_METHOD"] = "POST"

# Sync operation made async
await sync_to_async(request._load_post_and_files)()

# Restore original method
request.META["REQUEST_METHOD"] = initial_method
request.method = initial_method

return await get_response(request)

def sync_middleware(request: HttpRequest) -> Union[HttpResponse, Any]:
def sync_middleware(request: HttpRequest) -> ResponseType:
if (
request.method in TARGET_METHODS
and request.content_type != "application/json"
):
initial_method = request.method
request.method = "POST"
request.META["REQUEST_METHOD"] = "POST"

# Standard sync file/post data loading
request._load_post_and_files()

# Restore original method
request.META["REQUEST_METHOD"] = initial_method
request.method = initial_method

return get_response(request)

# Choose middleware based on the input handler's async nature
return async_middleware if iscoroutinefunction(get_response) else sync_middleware
Loading

0 comments on commit 398accd

Please sign in to comment.