Django REST에서 부분 업데이트 활성화

17534 단어 pythondjangoapirest

배경



데이터를 업데이트할 2개HTTP Request Methods가 있습니다.

PUT

The PUT method requests that the enclosed entity be stored under the supplied
URI. If the URI refers to an already existing resource, it is modified; if the
URI does not point to an existing resource, then the server can create the
resource with that URI.

PATCH

The PATCH method applies partial modifications to a resource.



우리가 볼 수 있듯이 PUT는 전체 데이터의 모든 리소스를 업데이트하는 반면 PATCH데이터의 일부를 업데이트합니다.

즉, PUT replace where PATCH 수정이라고 말할 수 있습니다.

따라서 이 기사에서는 PATCH 메서드를 찾을 것입니다.

HTTP에 대한 자세한 내용을 보려면 Hypertext Transfer Protocol - WIKI 을 참조하십시오.

앙트레



Django Rest Framework 에 대한 간단한 ModelViewSet 가 있고 사용자가 이 모델의 부분 데이터 필드를 업데이트할 수 있도록 하려고 한다고 가정해 보겠습니다. 어떻게 달성할 수 있습니까?

# views.py
from rest_framework import permissions, viewsets


class TodoViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer


DRF 의 문서 및 핵심을 검색한 후 ModelViewSet 일부 Mixins 상위 클래스를 상속하고 kwargs 에서 기본 부분UpdateModelMixin을 재정의해야 함을 발견했습니다.

# viewsets.py
# https://github.com/encode/django-rest-framework/blob/91916a4db1/rest_framework/viewsets.py

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass


아래 9행에서 확인할 수 있습니다.

# https://github.com/encode/django-rest-framework/blob/91916a4db14cd6a06aca13fb9a46fc667f6c0682/rest_framework/mixins.py#L64


class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)


해결책



따라서 아래와 같이 update 함수를 재정의하면 됩니다.

# views.py
from rest_framework import permissions, viewsets


class TodoViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)


클린 솔루션



프로그래밍의 깨끗한 면을 위해서는 분리하여 유지 관리 및 테스트를 위해 Mixin로 사용하는 것이 좋습니다.

# utils.py


class EnablePartialUpdateMixin:
    """Enable partial updates

    Override partial kwargs in UpdateModelMixin class
    https://github.com/encode/django-rest-framework/blob/91916a4db14cd6a06aca13fb9a46fc667f6c0682/rest_framework/mixins.py#L64
    """
    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)


아래와 같이 사용하세요.

# views.py
from rest_framework import permissions, viewsets
from .utils import EnablePartialUpdateMixin


class TodoViewSet(EnablePartialUpdateMixin, viewsets.ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer


부록



아래에서 TodoViewSet의 modelserializer 클래스를 찾을 수 있습니다.

또한 이 리포지토리에서 전체 코드 세부 정보를 찾을 수 있습니다. YADRTA

# models.py


class Task(BaseModelMixin):
    STATES = (
        ("todo", "Todo"),
        ("wip", "Work in Progress"),
        ("suspended", "Suspended"),
        ("waiting", "Waiting"),
        ("done", "Done"),
    )

    title = models.CharField(max_length=255, blank=False, unique=True)
    description = models.TextField()
    status = models.CharField(max_length=15, choices=STATES, default="todo")
    tag = models.ForeignKey(to=Tag, on_delete=models.DO_NOTHING)
    category = models.ForeignKey(to=Category, on_delete=models.DO_NOTHING)

    class Meta:
        ordering = ("title",)

    def __str__(self):
        return f"{self.created_by}:{self.title}"



# serializers.py
from rest_framework import serializers


class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = base_model_mixin_fields + [
            "title",
            "description",
            "status",
            "tag",
            "category",
        ]


모두 완료되었습니다!


변경 로그
  • 2020-10-26 : 배경 하위 섹션 추가
  • 좋은 웹페이지 즐겨찾기