41

I can not save the image in this ImageField.

when sending data back:

{
    "image": ["No file was submitted. Check the encoding type on the form."]
}

model.py

class MyPhoto(models.Model):
    owner = models.ForeignKey('auth.User', related_name='image')
    image = models.ImageField(upload_to='photos', max_length=254)

serializers.py

class PhotoSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = MyPhoto
        fields = ('url', 'id', 'image', 'owner')
        owner = serializers.Field(source='owner.username')

view.py

class PhotoList(APIView):
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)

    def get(self, request, format=None):
        photo = MyPhoto.objects.all()
        serializer = PhotoSerializer(photo, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def post(self, request, format=None):
       serializer = PhotoSerializer(data=request.DATA)
       if serializer.is_valid():
           serializer.save()
           return Response(serializer.data, status=status.HTTP_201_CREATED)
       return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def pre_save(self, obj):
        obj.owner = self.request.user


class PhotoDetail(APIView):

    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)

    def get_object(self, pk):
        try:
            return MyPhoto.objects.get(pk=pk)
        except MyPhoto.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        photo = self.get_object(pk)
        serializer = PhotoSerializer(photo)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        photo = self.get_object(pk)
        serializer = PhotoSerializer(photo, data=request.DATA)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        photo = self.get_object(pk)
        photo.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def pre_save(self, obj):
        obj.owner = self.request.user

url.py

urlpatterns = patterns('',
    url(r'^$', 'main.views.main_page'),
    url(r'^api/photo/$', views.PhotoList.as_view(), name='myphoto-list'),
    url(r'^api/photo/(?P<pk>[0-9]+)/$', views.PhotoDetail.as_view(), name='myphoto-detail'),)

curl

curl -X POST -S \
  -H 'Content-Type: application/json' \
  -u "michael:bush_pass" \
  --data-binary '{"owner":"/users/1/", \
    "image":"/Users/test/Downloads/1383310998_05.jpg"}' \
  127.0.0.1:8000/api/photo/
JJD
  • 50,076
  • 60
  • 203
  • 339
Mr.Ocean
  • 421
  • 1
  • 6
  • 9

5 Answers5

40

I think you can use request.data instead after django rest framework 3.0. The usage of request.DATA and request.FILES is now pending deprecation in favor of a single request.data attribute that contains all the parsed data.

You can check it from here

Scofield77
  • 917
  • 10
  • 16
  • 5
    This works, as an aside for some reason you cannot access the image data using `serializer.data['file_field']`, you must instead use `serializer.validated_data['file_field']` - caught me out but spotted it in @ckman's answer! – Ben Jan 27 '16 at 15:07
26

You seem to be missing the request.FILES argument to the serializer constructor in the your post and put handlers.

serializer = PhotoSerializer(data=request.DATA, files=request.FILES)
Kevin Stone
  • 8,831
  • 41
  • 29
  • 4
    This has not been correct since 2014: https://www.django-rest-framework.org/community/3.0-announcement/#request-objects – Rob Nov 11 '20 at 07:06
10

Uploading image files with Django Rest Framework:

models.py:

class MyPhoto(models.Model):
    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to='myphoto/%Y/%m/%d/', null=True, max_length=255)

serializers.py:

class MyPhotoSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyPhoto
        fields = ('id', 'name', 'image')

views.py:

class PhotoList(APIView):
    def post(self, request, format=None):
        serializer = MyPhotoSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Hope it helps someone.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • How does one upload image to this implementation @Orions ? – Pedrum Jul 17 '16 at 23:03
  • @Pedrum In my answer, I have used Django-Rest-Framework's `serializer` for the model: `MyPhoto`. When user submits a post request, Image gets uploaded or saved to the path mentioned in the model (path includes year, month and daywise folders). Let me know if it is still not clear. – Ajeet Shah Jul 18 '16 at 19:51
  • I am getting this error "detail": "Multipart form parse error - Invalid boundary in multipart: None" – Rajiv Sharma Aug 08 '17 at 07:39
5

Following should work if you are posting the image as base64 string and your serializer set accordingly and it inherits serializer.Serializer

 # views.py 
import base64
import os
from django.core.files import File 

class PhotoList(APIView):
    def post(self,request,format=None):
        serializer = PhotoSerializer(data=request.data)
        if serializer.is_valid():
            # access the data as serializer.validated_data['keys']
            # save the MyPhoto obj lets call it myphoto
            # get the base64 string 
            imgstr64 = serializer.validated_data['corresponding filed in the serializer']
            imgdata = base64.b64decode(imgstr64)
            fname = '/tmp/%s.jpg'%(str(myphoto.id))
            with open(fname,'wb') as f:
                f.write(imgdata)
            imgname = '%s.jpg'%(str(myphoto.id))
            myphoto.image.save(imgname,File(open(fname,'r')))
            os.remove(fname)
chandan
  • 964
  • 1
  • 19
  • 26
0
**
Django Rest Framework Image Upload
views.py
    class FileUploadView(APIView):
    permission_classes = []
    parser_class = (FileUploadParser,)

    @csrf_exempt
    def uploatuserprofile( request):

        #fetches specific user image
        if request.method=='GET':
            user_data=JSONParser().parse(request)
            obj=UserProfile.objects.filter(user=user_data["user"])
            serializer=UserProfileSerializer(obj,many=True)
            return JsonResponse(serializer.data,safe=False)



        if request.method == 'POST':
            # print('=====================================================================================>',request.FILES['profile_image'])
            
            # print("##################################################################################### ",request.POST['user'])
            try:
                s = UserProfile.objects.create(user_id = request.POST['user'], profile_image=request.FILES['profile_image'])
                s.save()
            except:
                return JsonResponse('Failed to upload Integrity error',safe=False)

            

            # file_serializer=UserProfileSerializer(request.POST,request.FILES)
        
            # if file_serializer.is_valid():
            #     file_serializer.save()
            return JsonResponse('profile uploded Sucessfully!!',safe=False)
        return JsonResponse('Failed to upload',safe=False)

urls.py of application

 url(r'^uploatuserprofile/$',views.FileUploadView.uploatuserprofile),


urls.py of project
from django.conf import settings
from django.conf.urls.static import static

from django.contrib import admin
from django.urls import path
from django.conf.urls import url,include
urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^',include('ChatApp.urls'))
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

models.py

class UserProfile(models.Model):
    user = models.ForeignKey(Users,on_delete=models.CASCADE)
    profile_image = models.ImageField(upload_to='images/', blank=True, null=True)



    def __str__(self):
        return self.profile_image.name





setting.py

STATIC_URL = '/images/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "images"),

]
STATIC_DIR = os.path.join(BASE_DIR, 'images')
# Base url to serve media files
MEDIA_URL = '/media/'

# Path where media is stored
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')`enter code here`**
  • 1
    Welcome to StackOverflow. While this code may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit](https://stackoverflow.com/posts/64893657/edit) your answer to add explanations and give an indication of what limitations and assumptions apply. – Ruli Nov 18 '20 at 13:36