Django REST Framework image upload
Asked Answered
A

4

42

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.

Acidulent answered 8/8, 2017 at 9:10 Comment(5)
Remove the paranthesis, serializer_class = ProductSerializer.. If you are using ModelViewSet, then you don't need to write anything more... ViewSet would handle pretty much everything for you.Hyacinthhyacintha
Ok, thanks, and how can I upload image with postman, or some Ajax request?Acidulent
When I use that in my model, I get a ValueError("Cannot serialize function: lambda")Dewan
@Rony Azrak, I'he just updated the question with a solution that works. use method productFile Acidulent
Can you send me your code to post data in model with image file I'm wondering for it..my code show me bad request 400 http://....Golanka
P
34

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

Panpipe answered 8/8, 2017 at 11:9 Comment(6)
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.Panpipe
Thank you! Can I have url with method "PUT" like /api/products/33/upload_docs ?Acidulent
yes you can of course but I didn't check if you can upload with PUT method or notPanpipe
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! :)Acidulent
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 filenamePanpipe
problem was with parser, I used FileUploadParser instead of MultiPartParser :) Thank you!Acidulent
L
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
    
Lawlor answered 17/3, 2019 at 9:35 Comment(2)
Have you tried to use MultiPartParser in views? Also I would recommend you to make new endpoint to 'upload_image' in ImageViewSetAcidulent
can you tell how to update this in request.Ontologism
D
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)),
]
Dressler answered 11/2, 2021 at 7:5 Comment(1)
this is best way to do it. in my thinking. thanksObviate
R
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)
Rok answered 30/3, 2022 at 3:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.