2017-11-24 27 views
1

this과 같은 쓰기 가능한 중첩 serializer를 만드는 방법과 일반 외래 키 (here)를 직렬화하는 방법에 대한 예제가 있습니다.Django Rest Framework : 일반 외래 키를 사용하여 쓰기 가능한 중첩 serializer

하지만 동시에 둘 다 수행하는 방법, 즉 일반 외래 키 필드에 대해 중첩 된 쓰기 가능한 직렬기를 만드는 방법을 찾을 수 없습니다.

class RecurringMeetingRelatedField(serializers.RelatedField): 
    def to_representation(self, value): 
     if isinstance(value, DailyMeeting): 
      serializer = DailyMeetingSerializer(value) 
     elif isinstance(value, WeeklyMeeting): 
      serializer = WeeklyMeetingSerializer(value) 
     else: 
      raise Exception('Unexpected type of tagged object') 
     return serializer.data 


class MeetingSerializer(serializers.ModelSerializer): 
    recurring_meeting = RecurringMeetingRelatedField() 

    class Meta: 
     model = Meeting 
     fields = '__all__' 

내가 : 내 serializers.py에서 사용자 정의 필드를 만든 다음

class Meeting(models.Model): 
    # More fields above 
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) 
    object_id = models.PositiveIntegerField() 
    recurring_meeting = GenericForeignKey('content_type', 'object_id') 

class DailyMeeting(models.Model): 
    meeting = GenericRelation(Meeting) 
    # more fields 

class WeeklyMeeting(models.Model): 
    meeting = GenericRelation(Meeting) 
    # more fields 

: 내 모델에서

중 하나 DailyMeeting 또는 WeeklyMeeting처럼 될 수있는 GenericForeignKeyMeeting 모델이 다음과 같은 JSON을 전달합니다.

{ 
    "start_time": "2017-11-27T18:50:00", 
    "end_time": "2017-11-27T21:30:00", 
    "subject": "Test now", 
    "moderators": [41], 
    "recurring_meeting":{ 
     "interval":"daily", 
     "repetitions": 10, 
     "weekdays_only": "True" 
     } 
} 
(210)

그러나 문제는 나는 다음과 같은 오류가 발생하고 있다는 것입니다 :

AssertionError: Relational field must provide a queryset argument, override get_queryset , or set read_only= True .

왜 관계형 필드 read_only를이어야 하는가? 내가 read_only으로 설정하면 시리얼 화기의 data으로 전달되지 않습니다.

어떤 종류의 쿼리 세트를 제공해야합니까?

+0

내가 시나리오를 확인하지 않은하지만 당신은 API를 ..에서 recurring_meeting을 통과 필요 없다 (그 시리얼 라이저() 메소드를 만들 추가) 그래서 당신은 설정할 수 있습니다''' –

+0

을 당신이 경우 read_only''' ''read_only''로 설정하면''create()''메소드에 전달 된''validated_data''에 아무것도 없습니다. 따라서이 경우 recurring_meeting은 완전히 무시됩니다. – Galil

답변

3

to_internal_value도 구현해야하며 일반 Field 클래스 만 사용할 수 있습니다.

from rest_framework.fields import Field 

class RecurringMeetingRelatedField(Field): 
    def to_representation(self, value): 
     if isinstance(value, DailyMeeting): 
      serializer = DailyMeetingSerializer(value) 
     elif isinstance(value, WeeklyMeeting): 
      serializer = WeeklyMeetingSerializer(value) 
     else: 
      raise Exception('Unexpected type of tagged object') 
     return serializer.data 

    def to_internal_value(self, data): 
     # you need to pass some identity to figure out which serializer to use 
     # supose you'll add 'meeting_type' key to your json 
     meeting_type = data.pop('meeting_type') 

     if meeting_type == 'daily': 
      serializer = DailyMeetingSerializer(data) 
     elif meeting_type == 'weekly': 
      serializer = WeeklyMeetingSerializer(data) 
     else: 
      raise serializers.ValidationError('no meeting_type provided') 

     if serializer.is_valid(): 
      obj = serializer.save() 
     else: 
      raise serializers.ValidationError(serializer.errors) 

     return obj 

검증은 예외가 발생합니다 다른 경우 RecurringMeetingRelatedFieldMeetingSerializer 검증 데이터에서 잘 다음 만든거야 객체를 갔다합니다.

+0

좋은 답변입니다! 감사! 방금 전체''meeting' 개체를 업데이트 할 때 중첩 된''recurring_meeting'' 필드는 업데이트되지 않지만 대신 새로운''recurring_meeting''이 생성된다는 것을 알았습니다. 만약 당신의 솔루션에 아무런 상관이 없다면, 아무튼 관련이 있는지 물어보십시오 ... – Galil

+0

@ 갤릴 나는 업데이트와 삭제에 대해 생각하지 않았습니다. 지금 당장 PC가 없으므로 솔루션을 테스트 할 수 없습니다. 그러나 업데이트 호출에서 json의'recurring_meeting' 필드를 제외하고'Required = False'를'RecurringMeetingSerializer'에 추가하면,'to_internal_value' 호출을 건너 뛰게됩니다. –

0

이 경우 Meeting serializer에서 RecurringMeetingRelatedField을 사용하는 대신 다음과 같은 중첩 된 serializer를 정의 할 수 있습니다.

class RecurringMeetingSerializer(serializers.Serializer): 
    interval = serializers.CharField() 
    repetitions = serializers.IntegerField() 
    weekdays_only = serializers.BooleanField() 

    class Meta: 
     fields = '__all__' 


class MeetingSerializer(serializers.ModelSerializer): 
    recurring_meeting = RecurringMeetingSerializer() 

    class Meta: 
     model = Meeting 
     exclude = ['object_id', 'content_type'] 

    def create(self, validated_data): 
     recurring_meeting = validated_data.pop('recurring_meeting') 

     if recurring_meeting['interval'] == 'daily': 
      instance = DailyMeeting.objects.create(**recurring_meeting) 
      type = ContentType.objects.get_for_model(instance) 
     else: 
      instance = WeeklyMeeting.objects.create(**recurring_meeting) 
      type = ContentType.objects.get_for_model(instance) 

     meeting = Meeting.objects.create(content_type=type, 
             object_id=instance.id) 

     return meeting