Using Celery to handle uploads in django


I was wondering how I can use Celery workers to handle file uploads. So I tried implementing it on a simple class. I overrided the create class in my ModelViewSet. But apparently Django’s default json encoder does not serialize ImageFields (Lame). I’ll really appreciate it if you guys could tell me how I can fix this. Here is what I came up with:

class ProductImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductImage
        fields = ['id', 'image']

from time import sleep
from celery import shared_task
from .models import ProductImage

def upload_image(product_id, image):
    print('Uploading image...')
    product = ProductImage(product_id=product_id, image=image)

class ProductImageViewSet(ModelViewSet):
    serializer_class = ProductImageSerializer

    def get_queryset(self):
        return ProductImage.objects.filter(product_id=self.kwargs['product_pk'])

    def create(self, request, *args, **kwargs):
        product_id = self.kwargs['product_pk']
        image = self.request.FILES['image']
        image_data =
        upload_image.delay(product_id, image_data)

        return Response('Thanks')

and here’s the my model containing my ImageField:

class ProductImage(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
    image = models.ImageField(upload_to='store/images', validators=[validate_image_size])

Hello everyone earlier I posted a solution for this question and even though that solution worked properly, I found a better solution.
Encoding and Decoding binary files using base64 makes them larger and that is not something we want. So a better solution is to temporarily save the uploaded file on the disk, pass the path to our celery worker to upload it and create a ProductImage instance in our database and then delete the file we saved on the disk .

Here’s how to implement it:

from time import sleep
from celery import shared_task
from .models import ProductImage
from django.core.files import File
from import FileSystemStorage
from pathlib import Path

def upload(product_id, path, file_name):

    print('Uploading image...')

    storage = FileSystemStorage()

    path_object = Path(path)

    with'rb') as file:
        picture = File(file,

        instance = ProductImage(product_id=product_id, image=picture)



In you should override the create method of the ProductImage serializer like this:

    def create(self, validated_data):
        product_id = self.context['product_id']
        image_file = self.context['image_file']
        storage = FileSystemStorage()
        = storage.get_available_name(image_file), File(image_file))

        return upload.delay(product_id=product_id, path=storage.path(,

You should also override the create method in ProductImage’s ViewSet to provide the image file for your serializer’s context:

    def create(self, request, *args, **kwargs):
        product_id = self.kwargs['product_pk']
        image_file = self.request.FILES['image']
        serializer = ProductImageSerializer(
                'product_id': product_id,
                'image_file': image_file
        return Response('Upload Started...')