Django rest framework one to one relation

前端 未结 2 509
说谎
说谎 2021-02-05 10:59

So I have follwoing models:

class A(models.Model):
  name = models.CharField()
  age = models.SmallIntergerField()

class B(models.Model):
  a = models.OneToOneF         


        
相关标签:
2条回答
  • 2021-02-05 11:47

    I know this is an old post but I came across this and after some research and reading through the Django Rest Framework documentation So a quick search I found that you could use the "related_name" parameter for reverse relationships as stated here

    reverse relationships are not automatically included by the ModelSerializer and HyperlinkedModelSerializer classes. To include a reverse relationship, you must explicitly add it to the fields list.

    For example:

        class AlbumSerializer(serializers.ModelSerializer):
            class Meta:
            fields = ['tracks', ...]
    

    You'll normally want to ensure that you've set an appropriate related_name argument on the relationship, that you can use as the field name.

    For example:

        class Track(models.Model):
            album = models.ForeignKey(Album, related_name='tracks', 
                    on_delete=models.CASCADE)
         ...
    

    If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the fields argument.

    For example:

        class AlbumSerializer(serializers.ModelSerializer):
           
            class Meta:
                fields = ['track_set', ...]
    

    Also, see the Django documentation on reverse relationships for more details.

    0 讨论(0)
  • 2021-02-05 11:50

    I just encountered the same problem, it would indeed be useful to make the response structure less tied to the underlying model structure. Here's my take :

    Reading is easy

    Serializer fields have a source parameter, which can take dotted names to traverse attributes.

    class ABSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = A
            fields = ['name', 'age', 'salary']
    
        salary = serializer.IntegerField(source='b.salary') # this is your related_name
    

    Writing is ... not officially supported

    Validated data will show a nested structure, and the standard create and update methods will choke trying to assign a data dict to a OneToOneField. The good news is that you can work around it by overriding create and update methods. Here's an example with update :

    class ABSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = A
            fields = ['name', 'age', 'salary']
            related_fields = ['b']
    
        salary = serializer.IntegerField(source='b.salary') # this is your related_name
    
        def update(self, instance, validated_data):
            # Handle related objects
            for related_obj_name in self.Meta.related_fields:
    
                # Validated data will show the nested structure
                data = validated_data.pop(related_obj_name)
                related_instance = getattr(instance, related_obj_name)
    
                # Same as default update implementation
                for attr_name, value in data.items():
                    setattr(related_instance, attr_name, value)
                related_instance.save()
            return super(ABSerializer,self).update(instance, validated_data)
    

    Of course, this example is very simplistic, doesn't do any exception handling, and won't work with more deeply nested objects... but you get the idea.

    Another option

    You could also create a read-write flavor of SerializerMethodField, which would consider both a getter and a setter, however that would probably end up being far more verbose in the end.

    Hope that helps !

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