Skip to content

Commit

Permalink
reinstate AllowPUTAsCreateMixin
Browse files Browse the repository at this point in the history
overenthusiastically removed
  • Loading branch information
dimbleby committed Jul 12, 2023
1 parent 70e41e3 commit 5710e4f
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 1 deletion.
3 changes: 2 additions & 1 deletion hunt/apiviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from hunt.constants import HINTS_PER_LEVEL
from hunt.models import Hint, Level
from hunt.third_party.apimixin import AllowPUTAsCreateMixin

T = TypeVar("T", bound="Model")
if TYPE_CHECKING:
Expand Down Expand Up @@ -51,7 +52,7 @@ class Meta:
]


class LevelViewSet(ModelViewSet[Level]):
class LevelViewSet(AllowPUTAsCreateMixin, ModelViewSet[Level]):
queryset = Level.objects.all().order_by("number")
serializer_class = LevelSerializer
http_method_names = [ # noqa: RUF012
Expand Down
59 changes: 59 additions & 0 deletions hunt/third_party/apimixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, TypeAlias

from django.http import Http404
from rest_framework import status
from rest_framework.request import clone_request
from rest_framework.response import Response

if TYPE_CHECKING:
from django.db.models import Model
from rest_framework.request import Request
from rest_framework.viewsets import GenericViewSet

_Base: TypeAlias = GenericViewSet[Model]
else:
_Base: TypeAlias = object


# https://gist.github.com/tomchristie/a2ace4577eff2c603b1b
class AllowPUTAsCreateMixin(_Base):
"""
The following mixin class may be used in order to support PUT-as-create
behavior for incoming requests.
"""

def update(
self,
request: Request,
*args: Any, # noqa: arg0001
**kwargs: Any,
) -> Response:
partial = kwargs.pop("partial", False)
instance = self.get_object_or_none()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)

if instance is None:
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
lookup_value = self.kwargs[lookup_url_kwarg]
extra_kwargs = {self.lookup_field: lookup_value}
serializer.save(**extra_kwargs)
return Response(serializer.data, status=status.HTTP_201_CREATED)

serializer.save()
return Response(serializer.data)

def partial_update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
kwargs["partial"] = True
return self.update(request, *args, **kwargs)

def get_object_or_none(self) -> Any:
try:
return self.get_object()
except Http404:
if self.request.method == "PUT":
self.check_permissions(clone_request(self.request, "POST"))
else:
raise

0 comments on commit 5710e4f

Please sign in to comment.