Django Rest Framework upload file to a method

2020-02-09 11:22发布

问题:

So i have been trying to upload a file to a method using DRF with no luck so far.

I was able to upload to a ModelViewSet using (FormParser, MultiPartParser,) with no problems, but i really need to use it in something like this http://localhost:8000/api/v1/women/{pk}/upload_avatar/ where i want to first filter the woman by id and upload to her avatar (which is a foreign key to a multimedia model). I tried using a nested resource library with no luck.

So far i have in my modelviewset:

class WomenNativePassportViewSet(viewsets.ModelViewSet):
    queryset = Women.objects.all()
    serializer_class = WomenNativePassportSerializer
    authentication_classes = (NoAuthentication,)
    permission_classes = (AllowAny,)
    parser_classes = (FormParser, MultiPartParser,)

    @detail_route(
        methods=['post', 'put', 'patch', 'get'], permission_classes=[AllowAny],
        authentication_classes=[NoAuthentication], serializer_class=MultimediaSerializer,
        parser_classes=(FormParser, MultiPartParser,)
    )
    def upload_avatar(self, request, pk=None, *args, **kwargs):
        if 'POST' in request._method or 'PATCH' in request._method:
            # Write code to save the file??
        else:
            multimedia = Multimedia.objects.filter(user_profiles_avatares__pk=pk)
            page = self.paginate_queryset(multimedia)
            serializer = self.get_pagination_serializer(page)
        return Response(serializer.data)

My models:

class Women(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    avatar = models.ForeignKey(
        'core.Multimedia', blank=True, null=True,
        related_name='user_profiles_avatares'
    )

class Multimedia(models.Model):
    file = models.FileField(upload_to=upload_to, null=True, blank=True)
    thumbnail = models.FileField(upload_to=upload_to, null=True, blank=True)

Basically i want to know if this is the right path i am taking, and if yes how can i properly save the uploaded file in the model??

回答1:

Here is some code of what i did to overcome this problem. Although Kevin Brown answer probably works, i find my code a little "easier" approach:

    @detail_route(
        methods=['post', 'put', 'patch', 'get'], permission_classes=[AllowAny],
        authentication_classes=[NoAuthentication], serializer_class=MultimediaSerializer,
        parser_classes=(FormParser, MultiPartParser,)
    )
    def upload_avatar(self, request, pk=None):
        # Because we are using nested resources this was the only way i found to
        # upload a file. Maybe there is a better way
        if request.method in ['PATCH', 'POST']:
            avatar = request.FILES.get('avatar')
            if not avatar:
                return Response(status=404)

            try:
                woman = WomenNativePassport.objects.get(pk=pk)
            except WomenNativePassport.DoesNotExist:
                return Response(status=404)
            else:
                request.FILES['thumbnail'] = request.FILES['avatar']
                serializer = AvatarSerializer(
                    data=request.DATA, files=request.FILES
                )
                if serializer.is_valid():
                    woman.avatar.thumbnail.save(str(avatar), File(avatar))
                    return Response(status=204)
                else:
                    return Response(status=404)
        else:
            multimedia = Multimedia.objects.filter(user_profiles_avatares__pk=pk)
            page = self.paginate_queryset(multimedia)
            serializer = self.get_pagination_serializer(page)
            return Response(serializer.data)


# serializer 

class AvatarSerializer(serializers.Serializer):
    thumbnail = serializers.ImageField()


回答2:

Any uploaded files should be available in request.FILES, a dictionary keyed by the field that they was used when uploading. Once you have the file, it's a matter of handling it similar to any other uploaded file in Django.

If you can, I would use a second serializer that wraps the Multimedia model so the image validation and saving can be done automatically through Django REST Framework. There is an ImageField that will automatically validate the image by Pillow which you can use on the serializer.