Okira
Okira

Reputation: 52

Upload an Image to Django Rest Framework using Requests Library

I am trying to make an api endpoint for creating a post, the user can choose whether they want to upload a text(tweet) or an image alone or both, I have a validate method in my serializer for if no image nor text is sent, but it's raising the error on every try regardless if what I sent it. Am not entirely sure if this is a serializer class error or the script I wrote for sending the POST request

import os
import requests
from PIL import Image

ENDPOINT = "http://0.0.0.0:8000/"

IMG = os.path.join(os.getcwd(), "img/img.jpg")


def send_request(method="GET", path="/", data=None, img_path=None):
    if data is None:
        data = {}
    if img_path is not None:
        with open(img_path, 'rb') as image:
            img_file = {"image": image}
            req = requests.request(method, ENDPOINT + path, data=data, files=img_file)
    else:
        req = requests.request(method, ENDPOINT + path, data=data)
    return req.text


res = send_request(method="POST", path="api/posts/create/", data={"user": 1, "content": ""}, img_path=IMG)

print(res)
from django.db import models
from django.conf import settings
import uuid
import os


class PostQuerySet(models.QuerySet):
    pass



class PostManager(models.Manager):
    def get_queryset(self):
        return PostQuerySet(self.model, using=self._db)


def upload_post_image(instance, filename):
    file_extension = filename.split('.')[-1]
    filename = f"{uuid.uuid4()}.{file_extension}"

    print(os.path.join())
    return os.path.join('post_image/', filename)



class Post(models.Model):
    user        = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content     = models.TextField(null=True, blank=True, max_length=255)
    image       = models.ImageField(null=True, upload_to=upload_post_image)

    def __str__(self):
        return str(self.content)[:50]

from rest_framework import serializers

from .models import Post


class PostSerializer(serializers.Serializer):

    class Meta:
        model = Post
        fields = ('user', 'content', 'image')

    def validate(self, data):
        content = data.get("content", None)
        image = data.get("image", None)
        if content == '':
            content = None

        if image is None and content is None:
            raise serializers.ValidationError("Content or an Image must be provided")
        return data
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import generics, mixins, permissions, authentication
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView

from .serializers import PostSerializer
from .models import Post


class PostManageAPIView(
    APIView,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    mixins.CreateModelMixin,
    mixins.ListModelMixin):

    def get(self, request, *args, **kwargs):
        print(self.request.GET)
        return Response({"message": "This is just a test"})


class PostDetailAPIView(generics.RetrieveAPIView):
    serializer_class = PostSerializer
    permission_classes = ()
    authentication_classes = ()
    queryset = Post.objects.all()

    def get_object(self, *args, **kwargs):
        kwargs = self.kwargs
        kw_id = kwargs.get('id')
        try:
            return Post.objects.get(id=kw_id)
        except ObjectDoesNotExist:
            return Response({})


class CreatePost(generics.CreateAPIView):
    serializer_class        = PostSerializer
    permission_classes      = ()
    authentication_classes  = ()

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

when I run the python script to send the request I always get the validation error saying content or an image must be provided

Upvotes: 2

Views: 1709

Answers (1)

Can Arsoy
Can Arsoy

Reputation: 116

You have to check if there is a file via the view's request.FILES attribute. The file you posted would not be in the POST body.

If there is no file posted, the request.FILES attribute will be an empty list.

Here is how you can do it: (Note that in CreateAPIView's create method, serializer already has the request object in its context)

class PostSerializer(serializers.Serializer):

class Meta:
    model = Post
    fields = ('user', 'content', 'image')

def validate(self, data):
    content = data.get("content", None)
    request = self.context['request']
    # you dont need to set content explicitly to None

    if not request.FILES and not content:
        raise serializers.ValidationError("Content or an Image must be provided")
    return data

Upvotes: 1

Related Questions