Disable creating nested objects in django rest framework

后端 未结 3 1204
孤城傲影
孤城傲影 2021-02-09 14:52

Hi,

Can you help me how to disable creating nested objects ?

I have serializers like this:
(Employee has ForeignKey to Team) <

相关标签:
3条回答
  • 2021-02-09 14:59

    Solved problem:

    class ReadEmployeeSerializer(serializers.ModelSerializer):
        team = TeamSerializer()
    
        class Meta:
            model = Employee
            fields = ('id', 'name', 'surname', 'team',)
    
    
    class WriteEmployeeSerializer(serializers.ModelSerializer):
    
        def from_native(self, data, files):
            data['team'] = data['team']['id']
            return serializers.ModelSerializer.from_native(self, data, files)
    
        def to_native(self, obj):
            return ReadEmployeeSerializer(obj).data
    
        class Meta:
            model = Employee
            fields = ('id', 'name', 'surname', 'team',)
    

    post/put method use primary key (WriteEmployeeSerializer) - before replace dict to primary key

    get method use full object (ReadEmployeeSerializer)

    0 讨论(0)
  • 2021-02-09 15:04

    I found that ModelSerializer.to_native() and ModelSerializer.from_native() don't exist in the latest version of DRF. I came up with the following derived from the accepted solution:

    class PlayerSerializer(serializers.ModelSerializer):
        class Meta:
            model = Player
            fields = ('id', 'name', 'team')
    
        def to_internal_value(self, data):
            # If team is not a dict, such as when submitting via the Browseable UI, this would fail.
            try:
                data['team'] = data['team']['id']
            except TypeError:
                pass
            return super(PlayerSerializer, self).to_internal_value(data)
    
        def to_representation(self, instance):
            return ReadPlayerSerializer(instance).data
    
    
    class ReadPlayerSerializer(serializers.ModelSerializer):
        team = TeamSerializer()
    
        class Meta(PlayerSerializer.Meta):
            pass
    

    Effectively, it seems that from_native is now to_representation, and to_native is no to_internal_value

    0 讨论(0)
  • 2021-02-09 15:22

    Okay, first of all, are you sure that your nested object is created? Because DRF was not designed to create nested objects, so this is a very strange behavior (more precisely, this is a work in progress, as stated by its creator, Tom Christie).

    Then, in order to have the serializer representation that you want, you must follow some rules:

    1. Create a simple serializer for each model (just like in your first code snippet)

    2. Add the FK relationship on the EmployeeSerializer: (be careful, for this to work, you must have your FK named 'team') team = serializers.RelatedField()

    3. Add the ManyToOne relationship on your TeamSerializer: (this is only needed if you also want to have all your employees when you get a Team object; if not, you can skip this part) employees = EmployeeSerializer(required=False, many=True)

    Also, you should remove the depth attribute from your serializer, he is the one that flattens your serialization (or you can just set it to 2). Hope this helps.

    UPDATE

    View for multiple serializers:

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return ReadEmployeeSerializer
        elif self.request.method == 'POST':
            return WriteEmployeeSerializer
        else:
            return DefaultSerializer
    
    class WriteEmployeeSerializer(serializers.ModelSerializer):
        class Meta:
            model = Employee
            fields = ('id', 'name', 'surname', 'team')
    
    class ReadEmployeeSerializer(serializers.ModelSerializer):
        team = TeamSerializer()
        class Meta:
            model = Employee
            fields = ('id', 'name', 'surname', 'team')
    

    A bit redundant, but should do the job.

    0 讨论(0)
提交回复
热议问题