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
  • Loading branch information
baseplate-admin committed Dec 10, 2024
1 parent 83ebb0c commit 5e55de1
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 5e55de1

Please sign in to comment.