使用请求库将图像上传到 Django Rest Framework

Upload an Image to Django Rest Framework using Requests Library

我正在尝试创建一个 api 端点来创建 post,用户可以选择是否要单独上传文本(推文)或图片或两者,我有一个如果没有发送图像或文本,我的序列化程序中的验证方法,但无论我发送的是什么,它都会在每次尝试时引发错误。 我不完全确定这是序列化程序 class 错误还是我为发送 POST 请求

编写的脚本
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)

当我 运行 python 脚本发送请求时,我总是收到验证错误,提示必须提供内容或图像

您必须通过视图的 request.FILES 属性检查是否有文件。您发布的文件不会在 POST 正文中。

如果没有文件发布,request.FILES 属性将为空列表。

您可以这样做:(请注意,在 CreateAPIView 的创建方法中,序列化程序的上下文中已经有请求对象)

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