40

I have model Product:

def productFile(instance, filename):
    return '/'.join( ['products', str(instance.id), filename] )

class Product(models.Model):
    ...

    image = models.ImageField(
        upload_to=productFile,
        max_length=254, blank=True, null=True
    )
    ...

Then I have serializer:

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = (
            ...
            'image',
            ...
        )

And then I have views:

class ProductViewSet(BaseViewSet, viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

How I can upload image with Postman? What is the best practices to upload image to model? Thank you.

Danila Kulakov
  • 1,082
  • 1
  • 12
  • 20

4 Answers4

32

you can create separate endpoint for uploading images, it would be like that:

class ProductViewSet(BaseViewSet, viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    @detail_route(methods=['post'])
    def upload_docs(request):
        try:
            file = request.data['file']
        except KeyError:
            raise ParseError('Request has no resource file attached')
        product = Product.objects.create(image=file, ....)

you can go around that solution

-- update: this's how to upload from postman enter image description here

Shehab ElDin
  • 584
  • 1
  • 8
  • 15
  • 3
    you can upload using postman by select `form-data` on body and select type to file and click on choose file, write `file` on key field see the update above. – Shehab ElDin Aug 08 '17 at 11:29
  • 1
    Thank you! Can I have url with method "PUT" like `/api/products/33/upload_docs` ? – Danila Kulakov Aug 08 '17 at 12:09
  • yes you can of course but I didn't check if you can upload with `PUT` method or not – Shehab ElDin Aug 08 '17 at 13:11
  • hm, I'm, just tried your solution, but I got error `{"detail":"Missing filename. Request should include a Content-Disposition header with a filename parameter."}` . Do you know how can I "turn off" this requirement? Once more Thank you! :) – Danila Kulakov Aug 08 '17 at 14:06
  • `filename` is required to upload, I think it's issue in postman, if you try any frontend code to test this api it's easy to set filename – Shehab ElDin Aug 08 '17 at 14:42
  • 1
    problem was with parser, I used FileUploadParser instead of MultiPartParser :) Thank you! – Danila Kulakov Aug 09 '17 at 11:17
24

I lately start Django and have same problem for upload image.

All steps that i done

  1. Install Pillow for using ImageField

    pip install Pillow
    
  2. In Settings.py add these lines

    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    MEDIA_URL = '/media/' # 'http://myhost:port/media/'
    
  3. Use ImageField in model.py (create nameFile function for create folder and name of file)

    def upload_to(instance, filename):
        return '/'.join(['images', str(instance.name), filename])
    
    class UploadImageTest(models.Model):
        name = models.CharField(max_length=100)
        image = models.ImageField(upload_to=upload_to, blank=True, null=True)
    
  4. serializer.py

    class ImageSerializer(serializers.ModelSerializer):
        class Meta:
            model = UploadImageTest
            fields = ('name', 'image')
    
  5. views.py

    class ImageViewSet(ListAPIView):
        queryset = UploadImageTest.objects.all()
        serializer_class = ImageSerializer
    
        def post(self, request, *args, **kwargs):
            file = request.data['file']
            image = UploadImageTest.objects.create(image=file)
            return HttpResponse(json.dumps({'message': "Uploaded"}), status=200)
    
  6. urls.py: add this line

    path('upload/', views.ImageViewSet.as_view(), name='upload'),
    
  7. admin.py: add this line (for check in admin)

    admin.site.register(UploadImageTest)
    
  8. in terminal

    python manage.py makemigrations
    python manage.py migrate
    
Radesh
  • 13,084
  • 4
  • 51
  • 64
4

models.py

from django.db import models

class ImageUpload(models.Model):
    title = models.CharField(max_length=50)
    images = models.ImageField('images')

serializers.py

from rest_framework import serializers
from .models import ImageUpload

class ImageUploadSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = ImageUpload
        fields= (
            'title',
            'images'
        )

views.py

from rest_framework import viewsets
from .models import ImageUpload
from .serializers import ImageUploadSerializer

class ImageUploadViewSet(viewsets.ModelViewSet):
    queryset = ImageUpload.objects.all()
    serializer_class = ImageUploadSerializer

urls.py

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register(r'imageupload', views.ImageUploadViewSet)

urlpatterns = [
    path('imageupload', include(router.urls)),
]
stephendwolff
  • 1,382
  • 1
  • 13
  • 27
1

this worked for me

class UserAvatarUpload(ListAPIView):
    
    parser_classes = [MultiPartParser, FormParser]
    serializer_class = ImageSerializer

    def post(self, request, *args, **kwargs):
        username = request.data['username']
        file = request.data['image']
        user = MyModel.objects.get(username=username)
        user.image = file
        user.save()
        return Response("Image updated!", status=status.HTTP_200_OK)
Aditya Rajgor
  • 953
  • 8
  • 14