Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload image file using django rest framework in a single page application

I am trying to upload image using Vuejs and Django, but I can't figure out how to solve it.

This is the django side:

class UserDetail(models.Model):
    user = models.OneToOneField(User)
    profile_picture = models.ImageField(upload_to=create_file_path)

class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDetail
        fields = '__all__'

class UserDetailViewSet(viewsets.ModelViewSet):
    queryset = UserDetail.objects.all()
    serializer_class = UserDetailSerializer
    permission_classes = [AllowAny]

    @detail_route(permission_classes=[AllowAny], methods=['POST'], parser_classes=[FormParser, MultiPartParser])
    def create_or_update_profile_picture(self, request):
        user = request.user
        #
        # how to create or update user detail profile picture ?
        #

I am posting the data this way from Vuejs:

changeProfilePicture() {
    const file_input = document.getElementById('display_profile_image');
    const img = file_input.files[0];
    let formData = new FormData();
    formData.append("profile_picture", img);
    const url = this.$store.state.website + '/api/accounts/user-detail/none/create_or_update_profile_picture/';
    this.$http.post(url, formData)
        .then(function (response) {
            this.$store.dispatch('getUserDetail');
        })
        .catch(function (response) {
            console.log(response);
        });
}

How can I use the post data to create or update the request.user's profile_picture with Django and django rest framework inside the model viewset class, using default methods (create/update/partial_update) or by creating a new detail route?

like image 486
Robin Avatar asked May 30 '17 20:05

Robin


People also ask

How do I store images in Django?

In Django, a default database is automatically created for you. All you have to do is add the tables called models. The upload_to tells Django to store the photo in a directory called pics under the media directory. The list_display list tells Django admin to display its contents in the admin dashboard.

Why use Django Rest Framework instead of Django?

Its main benefit is that it makes serialization much easier. Django REST framework is based on Django's class-based views, so it's an excellent option if you're familiar with Django. It adopts implementations like class-based views, forms, model validator, QuerySet, and more.


1 Answers

Assuming your JS posts the request using 'multipart/form-data' (check this), you should be able to upload the image file when creating or updating the user. Also, make sure you send CSRF Token.

To be able to set the logo on its own, a detailed_route is a good way using a serializer limited to the logo. In the detailed route, if you want to upload log for logged in user (I saw you put none as an id), you can check that in the detail route before calling get_object which will get the userdetail instance.

class UserLogoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDetail
        fields = ['profile_picture']


class UserDetailViewSet(viewsets.ModelViewSet):
    queryset = UserDetail.objects.all()
    serializer_class = UserDetailSerializer
    permission_classes = [AllowAny]

    @detail_route(methods=['post'])
    def set_profile_picture(self, request, pk=None, format=None):
        if pk in ['none', 'self']: # shortcut to update logged in user without looking for the id
            try:
                userdetail = self.get_queryset().get(user=request.user)
            except UserDetail.DoesNotExist:
                userdetail = None
        else:
            userdetail = self.get_object()

        serializer = serializers.UserLogoSerializer(userdetail, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)            

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

If I recall correctly, permission_classes are the one set on the Viewset by default, and the default parsers should do the job.

like image 191
Michael Rigoni Avatar answered Sep 19 '22 16:09

Michael Rigoni