Django REST:上传和序列化多个图像

GRS*_*GRS 9 python django serialization django-rest-framework

我有2个模型Task,TaskImage它们是属于Task对象的图像集合.

我想要的是能够向我的Task对象添加多个图像,但我只能使用2个模型.目前,当我添加图片时,它不允许我上传它们并保存新对象.

settings.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Run Code Online (Sandbox Code Playgroud)

serializers.py

class TaskImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = TaskImage
        fields = ('image',)


class TaskSerializer(serializers.HyperlinkedModelSerializer):
    user = serializers.ReadOnlyField(source='user.username')
    images = TaskImageSerializer(source='image_set', many=True, read_only=True)

    class Meta:
        model = Task
        fields = '__all__'

    def create(self, validated_data):
        images_data = validated_data.pop('images')
        task = Task.objects.create(**validated_data)
        for image_data in images_data:
            TaskImage.objects.create(task=task, **image_data)
        return task
Run Code Online (Sandbox Code Playgroud)

models.py

class Task(models.Model):
    title = models.CharField(max_length=100, blank=False)
    user = models.ForeignKey(User)

    def save(self, *args, **kwargs):
        super(Task, self).save(*args, **kwargs)

class TaskImage(models.Model):
    task = models.ForeignKey(Task, on_delete=models.CASCADE)
    image = models.FileField(blank=True)
Run Code Online (Sandbox Code Playgroud)

但是,当我发布帖子请求时:

在此输入图像描述

我得到以下回溯:

文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/exception.py"在内部41. response = get_response(request)

文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py"在_get_response 187. response = self.process_exception_by_middleware(e,request)

_get_response中的文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py"185. response = wrapped_callback(request,*callback_args,**callback_kwargs)

在wrapped_view 58中输入文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/views/decorators/csrf.py".返回view_func(*args,**kwargs)

在视图95中输入文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py".返回self.dispatch(request,*args,**kwargs)

发送494中的文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py".response = self.handle_exception(exc)

handle_exception 454中的文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py"self.raise_uncaught_exception(exc)

发送491中的文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py".response = handler(request,*args,**kwargs)

在create 21. self.perform_create(serializer)中输入文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py"

perform_create 152中的文件"/Users/gr/Desktop/PycharmProjects/godo/api/views.py".serializer.save(user = self.request.user)

保存214中的文件"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/serializers.py".self.instance = self.create(validated_data)

创建67中的文件"/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py".images_data = validated_data.pop('images')

异常类型:/ api/tasks/Exception值的KeyError:'images'

JPG*_*JPG 12

问题描述由于此声明,
异常的起源是a .这是因为验证数据没有密钥.这意味着图像输入不会验证邮递员的图像输入. Django的POST请求店里的 ,所以我们用它来获取文件.此外,您希望一次上传多个图片.因此,您必须在上传图像时使用不同的image_names(在邮递员中). 把你改成这样,KeyErrorimagesInMemmoryUpload

request.FILESserializer


ModelViewSet

images_data = validated_data.pop('images')
Run Code Online (Sandbox Code Playgroud)



我不知道你的观点,但我想使用reverse foreignKey
令人难以置信的观点类

class TaskSerializer(serializers.HyperlinkedModelSerializer):
    user = serializers.ReadOnlyField(source='user.username')
    images = TaskImageSerializer(source='taskimage_set', many=True, read_only=True)

    class Meta:
        model = Task
        fields = ('id', 'title', 'user', 'images')

    def create(self, validated_data):
        images_data = self.context.get('view').request.FILES
        task = Task.objects.create(title=validated_data.get('title', 'no-title'),
                                   user_id=1)
        for image_data in images_data.values():
            TaskImage.objects.create(task=task, image=image_data)
        return task
Run Code Online (Sandbox Code Playgroud)


邮差控制台 在此输入图像描述

DRF-结果

class Upload(ModelViewSet):
    serializer_class = TaskSerializer
    queryset = Task.objects.all()
Run Code Online (Sandbox Code Playgroud)



更新
这是您的评论的答案.在Django _set正在捕获使用Task.看到这个官方文件.在这里,TaskImageOneToManyTask关系,所以如果你有一个TaskImage例子,你可以得到所有有关reverse look-up此实例task_img_set_all功能
这里是例子

{
        "id": 12,
        "title": "This Is Task Title",
        "user": "admin",
        "images": [
            {
                "image": "http://127.0.0.1:8000/media/Screenshot_from_2017-12-20_07-18-43_tNIbUXV.png"
            },
            {
                "image": "http://127.0.0.1:8000/media/game-of-thrones-season-valar-morghulis-wallpaper-1366x768_3bkMk78.jpg"
            },
            {
                "image": "http://127.0.0.1:8000/media/IMG_212433_lZ2Mijj.jpg"
            }
        ]
    }
Run Code Online (Sandbox Code Playgroud)

TaskImage.objects.filter(task_id=1)将等于KeyError

  • 当您创建 TaskImage (```TaskImage.objects.create(task=task, image=image_data)```) 时,不应该使用序列化程序创建它吗?如果不这样做,我会假设您绕过验证阶段,并在未经验证的情况下保存对象? (3认同)