programing

django REST 프레임워크에서 request.data를 수정하는 방법

mbctv 2023. 4. 1. 09:53
반응형

django REST 프레임워크에서 request.data를 수정하는 방법

저는 장고 REST 프레임워크를 사용하고 있습니다.

request.data = '{"id": "10", "user": "tom"}'

는 '하다'와 같은 싶어요."age": "30" 같은 하기 전에

    request.data = new_data
    response = super().post(request, *args, **kwargs)

두 가지 문제가 있습니다.

  1. request.data가 dict가 아닌 문자열로 제공되는 이유
  2. request.data 업데이트 방법

가 API인 APIView그런 다음 업데이트 기능을 사용하여 클라이언트 측에서 전송된 데이터를 잃지 않고 요청 데이터 개체를 확장해야 합니다.

request.data.update({"id": "10", "user": "tom"})

request.data는 문자열이 아닌 불변이어야 합니다.수정이 필요한 경우:

if isinstance(request.data, QueryDict): # optional
    request.data._mutable = True
request.data['age'] = "30"

인스턴스가 「」의 할 수 는, 「」입니다.QueryDictdict.

좋은 친구가 방금 내가 위에서 설명한 것보다 훨씬 간단한 방법으로 나를 학교에 데려갔다.

class CreateSomething(CreateAPIView):
    model = Something
    queryset = Something.objects.all()
    serializer_class = SomethingSerializer

    perform_create(self,serializer):
    def perform_create(self,serializer):
        ip = self.get_ip()
        ## magic here: add kwargs for extra fields to write to db
        serializer.save(ip_addr=ip)

    def get_ip(self):
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR',None)
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR',None)
        return ip

class SomethingSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(validators=[UniqueValidator(queryset=Something.objects.all())])
    fieldA = serializers.CharField()
    fieldB = serializers.CharField()

    class Meta:
        model = Customer2
        fields = ['email','fieldA','fieldB','ip_addr']
        read_only_fields = ['ip_addr']

일반적으로는 「일부러」입니다.request에서 drf는 "drf"입니다.rest_framework.request.Request★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」djangorestframework==3.8.2

    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data

다음 작업을 수행할 수 있습니다.

request._full_data = your_data

마치 json 끈처럼 생겼네요.이를 딕트로 변환하려면 다음 작업을 수행해야 합니다.

import json
data = json.loads(request.data)

다음으로 Atribut을 추가할 수 있습니다.

data['age'] = 30

그러면 예전 것을 그냥 바꿀 수 없을 것 같아서 새로 요청해야 할 것 같아요.이것은, /notes/: 에 투고하는 것을 전제로 하고 있습니다.

from rest_framework.test import APIRequestFactory
factory = APIRequestFactory()
request = factory.post('/notes/', data, format='json')

요청 오브젝트를 변경할 우려가 있는 경우 상세 복사를 사용하여 오브젝트를 복사하면 쉽게 변경할 수 있습니다.

사용방법:

from copy import deepcopy

# here is your other code and stuffs
data = deepcopy(request.data)

이제 데이터를 자유롭게 변경할 수 있습니다.

지금까지, 이것은 일반적인 관점을 사용하지 않는 한 내가 선호하는 변경 방법입니다.

이 방법의 단점이 있다면 아래에 코멘트를 달아주세요!

Framework)로 되어 있는 DRF(Dango REST Framework)로 되어 있습니다.ViewSet「」를 입니다.to_internal_value이치노

class MyModelViewSet(viewsets.ModelViewSet):
    authentication_classes = ...
    ...
    serializer_class = MyModelSerializer


class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = ('id', 'user', ...)

    def to_internal_value(self, data):
        instance = super(MyModelSerializer, self).to_internal_value(data)
        if "lastModified" in data:
            # instance["id"] = 10  # That's sketchy though
            instance["user"] = "tom"
        return instance

코멘트에 의하면:

"게시 전에 API에 필요한 필드 이름 aqs를 확인해야 하기 때문입니다."

'어울리다'를하셔야 합니다.Field대신 의 인수를 사용합니다.

이렇게 하면 오류 메시지의 일관성이 향상됩니다. 그렇지 않으면 사용자가 제공하지 않은 필드 이름의 오류가 발생합니다.

나는 이것을 다르게 다루었다.[ Create ]를 덮어씁니다.API View 생성 메서드는 다음과 같습니다.

class IPAnnotatedObject(CreateAPIView):
    model = IPAnnotatedObject
    queryset = IPAnnotatedObject.objects.all()
    serializer_class = IPAnnotatedObject
    def create(self, request, *args, **kwargs):
        request.data['ip_addr'] = self.get_ip()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        ## perform_create calls serializer.save() which calls the serializer's create() method
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def get_ip(self):
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR',None)
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR',None)
        return ip

대응하는 시리얼라이저 클래스는 다음과 같습니다.

class IPAnnotatedObjectSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(validators=[UniqueValidator(queryset=IPAnnotatedObject.objects.all())])
    password = serializers.CharField(write_only=True)
    ip_addr = serializers.IPAddressField(write_only=True)
    class Meta:
        model = IPAnnotatedObject
        fields = ['email','password','created_ip']

    def create(self, validated_data):
        email, password, created_ip = validated_data['email'], validated_data['password'],validated_data['created_ip']
        try:
            ipAnnoObject = IPAnnotatedObject.objects.create(email=email,password=make_password(password),ip_addr=ip_addr)
        except Exception as e:
            # you can think of better error handler
            pass
        return ipAnnoOjbect

다음을 수행했습니다.

import json

data = json.dumps(request.data)
data = json.loads(data)

data['age'] = 100

시점에서 변수 「」를 합니다.datarequest.data.

다른 답변도 좋지만 여기서 한 가지만 덧붙이고 싶었어요.

이제 두 가지 방법으로 업데이트 할 수 있습니다.request.data그러나 그 전에 오브젝트가 QueryDict인지 확인합니다(@mikebridge에서 이미 언급).

from django.http.request import QueryDict


if isInstance(request.data, QueryDict):
    request.data._mutable = True

그 후 request.data를 갱신하는 첫 번째 방법은 다음과 같습니다.

request.data.update({'key': 'new_value'})

이것은 정상적으로 동작합니다만, 갱신하는 request.data['key']가 리스트인 경우, 값은 에 의해서 완전하게 변경되지 않습니다.new_value그러나 오래된 목록에 추가되어 문제가 발생할 수 있으며 원하는 결과를 얻지 못할 수 있습니다.

이를 극복하기 위해, 즉 어떤 키의 값을 완전히 변경하려면 두 번째 방법을 사용합니다.

request.data['key'] = 'new_value'

그러면 값이 변경됩니다.request.data['key']에게 완전히new_value.

덮어쓸 수 있음is_validserializer 클래스에서는, 보다 읽기 쉬워집니다.

class YourSerializer
    
    # Don't forget it
    age = serializers.IntegerField()

    def is_valid(self, raise_exception: bool = ...) -> bool:
        self.initial_data["age"] = 30
        return super().is_valid(raise_exception)

언급URL : https://stackoverflow.com/questions/33861545/how-can-modify-request-data-in-django-rest-framework

반응형