简体   繁体   中英

How to assign DRF serializer read_only fields from views

Example code

# models.py
class Profile(models.Model):
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    ...

class Photo(models.Model):
    image = models.ImageField(upload_to='photos')
    profile = models.ForeignKey('Profile', on_delete=models.CASCADE, related_name='photos')
    ...

# serializers.py
class ProfileSerializer(serializers.ModelSerializer):
    photos = serializers.HyperlinkedRelatedField(many=True, view_name='photo-detail', read_only=True)

    class Meta:
        model = Profile
        fields = '__all__'

class PhotoSerializer(serializers.ModelSerializer):
    # How to assign this implicitly from view?
    profile = PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Face
        fields = '__all__'

My solution

# views.py
class ProfileViewSet(viewsets.ModelViewSet):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer

    @action(methods=['GET', 'POST'], detail=True, serializer_class=FaceSerializer)
    def photos(self, request, *args, **kwargs):
        profile = self.get_object()
        if request.method == 'GET':
            ...
        elif request.method == 'POST':
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid()
            # accessing validated_data
            # explicitly set profile read_only field
            serializer.validated_data['profile'] = profile
            self.perform_create(serializer)
            return Response(serializer.data)

Example call

curl -X POST http://localhost:8000/profiles/4/photos/ --form image=@photo_image.jpg

Expected behavior

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 123,
    "profile": 4,
    "image": "http://localhost:9000/media/photos/photo_image.jpg",
    ....
}

When passing photo image to endpoint /profile/<int:pk>/photos/ , Photo's ( read_only=True ) profile field have been set by extracted <int:pk> view parameter.

Question

Is there more elegant way to achieve this? I don't feel comfortable accessing serializer.validated_data and explicitly set profile value...

pass profile value in save() method of serializer, as

...
elif request.method == 'POST':
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid()
    
    return Response(serializer.data)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM