programing

Django REST Framework POST 중첩된 개체

mailnote 2023. 3. 22. 21:50
반응형

Django REST Framework POST 중첩된 개체

는 지금 장고 레스트 프레임워크에 약간의 문제가 있습니다.중첩된 개체가 포함된 개체를 게시하려고 합니다.

Here are my 여기 내 것이 있다serializers.py:

class ClassSerializer(serializers.ModelSerializer):
    class Meta:
        model = Class
        fields = ('number', 'letter')


class SubjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subject
        fields = ('title',)


class ExamSerializer(serializers.ModelSerializer):
    subject = SubjectSerializer()
    clazz = ClassSerializer()

    class Meta:
        model = Exam
        fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')
        depth = 1

    def create(self, validated_data):
        return Exam.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.__dict__.update(**validated_data)
        instance.save()

        return instance

And 그리고.create()부에서views.py:

def create(self, request):
    serializer = self.serializer_class(data=request.data)
    serializer.is_valid(raise_exception=True)
    self.perform_create(serializer)

    return Response(serializer.validated_data, status=status.HTTP_201_CREATED)

여기 우체부의 답변이 있습니다.

이 문제에 대해 댓글 좀 읽어봤지만 아직 안 돼요.나는 이 문제에 대한 몇 개의 게시물을 읽었지만 여전히 그것에 얽매여 있다.나는 몇 가지 방법으로 고칠 수 있지만 returning 법 치 지 직 있 습 니 구 i'되안 ways고 but복 it가 in several it still to다,했만고 is fix아"This field is required.".

네스트된 시리얼라이제이션의 문제를 다루고 있습니다.진행하기 전에 링크된 설명서를 읽어보십시오.

이 질문은 DRF의 복잡한 문제 영역에 관한 것이므로 시리얼라이저와 뷰셋의 구조를 이해하기 위해서는 몇 가지 설명과 논의가 필요합니다.

I will discuss the problem of representing your 나는 당신의 대리인 문제에 대해 논의할 것이다.Subject and 그리고.Class다른 HTTP 메서드에 대해 다른 데이터 표현을 사용하여 동일한 엔드포인트를 경유하는 데이터입니다.이는 일반적으로 사람들이 데이터를 중첩된 형식으로 표현하고 싶을 때 발생하는 문제이기 때문입니다.데이터는 예를 들어 드롭다운실렉터를 통해 사용자 인터페이스에 깨끗한 사용을 위한 충분한 정보를 제공하려고 합니다.

및 Framework된 오브젝트Django」 「Django REST Framework(DRF)」)를합니다.Subject ★★★★★★★★★★★★★★★★★」Class)을 클릭합니다.디폴트로는 Django를 사용한 정수 키 자동 증가입니다.다른 방법으로 참조하려면 이 항목에 대한 재정의를 작성해야 합니다.몇 가지 다른 옵션이 있습니다.

  1. 첫 번째 옵션은 작성 및 로직 업데이트입니다.다른 속성을 통해 클래스를 참조하고 직접 생성할 룩업을 작성하거나 참조할 키를 클래스의 기본 키로 설정하십시오.클래스 이름, UUID 또는 기타 속성을 프라이머리 데이터베이스 키로 설정할 수 있습니다.단, 하나의 필드(현시점에서는, 이 필드를 참조하고 있기 때문에,Class복합(숫자, 문자) 검색어로 구성된 복합 검색으로 모델을 만듭니다.은 '비밀번호'에서 수 .create view method의 경우)를 참조할 수 있지만, 이 가 있습니다.update및 PATCH의 ) (PUT patch PATCH ) 。
  2. 둘째, 내 생각에 바람직한 선택은 객체 표현을 전문화하는 것이다.기본 키를 통해 클래스를 참조하고 개체를 읽기 위한 직렬화기개체를 만들고 업데이트하기 위한 직렬화기를 만듭니다.이는 시리얼라이저 클래스를 상속하고 표현을 재정의하면 쉽게 달성할 수 있습니다.POST, PUT, PATCH 등의 요청에서 기본 키를 사용하여 클래스 참조 및 외부 키를 업데이트합니다.

옵션 1: create 및 update에서 임의의 Atribut을 사용하여 Class and Subject를 검색합니다.

중첩된 클래스 직렬화기를 읽기 전용으로 설정합니다.

class ExamSerializer(serializers.ModelSerializer):
    subject = SubjectSerializer(read_only=True)
    clazz = ClassSerializer(read_only=True)

보기의 작성을 재정의하여 자유 양식 속성에 대한 관련 클래스를 검색합니다.또한 DRF가 믹스인을 사용하여 이를 구현하는 방법도 확인하십시오.또, 이 기능을 무효로 할 필요가 있습니다.update사항을 올바르게 합니다.PATCH 및 (갱신) 지원PUT루트를 : (업데이트)

def create(self, request):
    # Look up objects by arbitrary attributes.
    # You can check here if your students are participating
    # the classes and have taken the subjects they sign up for.
    subject = get_object_or_404(Subject, title=request.data.get('subject'))
    clazz = get_object_or_404(
        Class, 
        number=request.data.get('clazz_number')
        letter=request.data.get('clazz_letter')
    )

    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save(clazz=clazz, subject=subject)
    headers = self.get_success_headers(serializer.data)

    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

옵션 2: 읽기 및 쓰기 전용 시리얼라이저를 사용하여 프라이머리 키를 사용합니다.이것은 관용적인 접근법입니다.

먼저 일반 조작에 사용하는 기본 ModelSerializer(POST, PUT, PATCH)를 정의합니다.

class ExamSerializer(serializers.ModelSerializer)
    class Meta:
        model = Exam
        fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')

그런 다음 필요한 필드를 데이터 읽기(GET)를 위해 제공하는 표현 유형으로 덮어씁니다.

class ExamReadSerializer(ExamSerializer):
     subject = SubjectSerializer(read_only=True)
     clazz = ClassSerializer(read_only=True)

그런 다음 ViewSet의 다른 작업사용할 직렬화기를 지정합니다.여기서는 읽기 작업에 대해 중첩된 제목 및 클래스 데이터를 반환하지만 업데이트 작업에는 기본 키만 사용합니다(훨씬 단순함).

class ExamViewSet(viewsets.ModelViewSet):
     queryset = Exam.objects.all()

     def get_serializer_class(self):
         # Define your HTTP method-to-serializer mapping freely.
         # This also works with CoreAPI and Swagger documentation,
         # which produces clean and readable API documentation,
         # so I have chosen to believe this is the way the
         # Django REST Framework author intended things to work:
         if self.request.method in ['GET']:
             # Since the ReadSerializer does nested lookups
             # in multiple tables, only use it when necessary
             return ExamReadSerializer
         return ExamSerializer

보시다시피 옵션2는 DRF(get_serializer_class 구현) 위에 수기 코드 3줄만 포함되어 있어 복잡성과 오류 발생 가능성이 상당히 낮아 보입니다.프레임워크의 논리로 오브젝트의 표현, 작성 및 갱신을 파악할 수 있습니다.

그 밖에도 많은 어프로치를 봐 왔지만, 지금까지의 어프로치에서는, DRF의 설계를 깔끔하게 활용해, 최소한의 코드로 유지되고 있습니다.

추가 수업을 하지 않고 보다 쉽게 접근할 수 있는 방법은 직접 시리얼라이제이션하는 것입니다.

class ExamSerializer(serializers.ModelSerializer):
    class Meta:
        model = Exam
        fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['subject'] = SubjectSerializer(
            Subject.objects.get(pk=data['subject'])).data
        data['clazz'] = ClassSerializer(
            Class.objects.get(pk=data['clazz'])).data
        return data

문제를 해결하려면 이 패키지 drf-rw-serializers를 사용할 수 있습니다.

다음의 2개의 시리얼라이저(읽기용과 쓰기용)를 사용하면 됩니다.

serializers.py

class ClassSerializer(serializers.ModelSerializer):
    class Meta:
        model = Class
        fields = ('number', 'letter')


class SubjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subject
        fields = ('title',)


class ExamSerializer(serializers.ModelSerializer):
    subject = SubjectSerializer()
    clazz = ClassSerializer()

    class Meta:
        model = Exam
        fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')

class WriteExamSerializer(serializers.ModelSerializer):
    subject = SubjectSerializer()
    clazz = ClassSerializer()

    class Meta:
        model = Exam
        fields = ('id', 'subject', 'clazz', 'topic', 'date', 'details')

    def create(self, validated_data):
        subject = validated_data.pop('subject', None)
        # logic to update subject
        clazz = validated_data.pop('clazz', None)
        # logic to update clazz
        return super().create(validated_data)

    def update(self, validated_data):
        subject = validated_data.pop('subject', None)
        # logic to update subject
        clazz = validated_data.pop('clazz', None)
        # logic to update clazz
        return super().update(validated_data)

api_module을 클릭합니다.화이

from drf_rw_serializers import generics

from .models import Exam
from .serializers import WriteExamSerializer, ExamSerializer


class ExamListCreateView(generics.ListCreateAPIView):
    queryset = Exam.objects.all()
    write_serializer_class = WriteExamSerializer
    read_serializer_class = ReadExamSerializer

DRF(Django Rest Framework)에 중첩된 JSON 개체를 게시하려고 할 때도 같은 문제가 있었습니다.

네스트된 시리얼라이저를 올바르게 작성(쓰기 가능한 네스트된 시리얼라이저의 문서 참조)한 후 브라우징 가능한 API를 사용하여 데이터를 게시/투고하여 동작하는지 테스트할 수 있습니다.JSON 개체를 게시/퍼트할 때 중첩된 모델에서 "This field is required" 오류가 여전히 표시되는 경우 요청의 내용 유형을 설정해야 할 수 있습니다.

답변은 제가 필요로 하는 해결책을 제시해 주었습니다.이 답변은 아래에 요약되어 있습니다.

$.ajax ({
  // Other parameters e.g. url, type
  data: JSON.stringify(data),
  dataType: "json",
  contentType: "application/json; charset=utf-8",
});

"contentType"을 설정하고 js 개체를 "string"해야 했습니다.

Serializer Method Field가 훨씬 더 간단하다고 생각합니다.

@validname' 솔루션처럼 보이지만 훨씬 더 읽기 쉽습니다.

class BlogSerializer(serializers.ModelSerializer):

    writer = serializers.SerializerMethodField()
    comments = serializers.SerializerMethodField()

    class Meta:
        model = Blog
        fields = '__all__'

    def get_comments(self, obj):
        return CommentSerializer(obj.comments.all(), many=True).data

    def get_writer(self, obj):
        return WriterSerializer(instance=obj.writer).data

언급URL : https://stackoverflow.com/questions/41312558/django-rest-framework-post-nested-objects

반응형