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

Posted

技术标签:

【中文标题】Django REST:上传和序列化多个图像【英文标题】:Django REST: Uploading and serializing multiple images 【发布时间】:2018-07-23 04:47:58 【问题描述】:

我有 2 个模型 TaskTaskImage,这是属于 Task 对象的图像集合。

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

settings.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

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

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)

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

我得到以下回溯:

文件 “/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)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py” 在 _get_response 185. response = Wrapped_callback(request, *callback_args, **callback_kwargs)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/views/decorators/csrf.py” 在wrapped_view 58. return view_func(*args, **kwargs)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py” 在视野中 95. return self.dispatch(request, *args, **kwargs)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py” 在调度中 494. 响应 = self.handle_exception(exc)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py” 在句柄异常中 454. self.raise_uncaught_exception(exc)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py” 在调度中 491. 响应 = 处理程序(请求,*args,**kwargs)

文件 “/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py” 在创建 21. self.perform_create(序列化器)

文件“/Users/gr/Desktop/PycharmProjects/godo/api/views.py”在 perform_create 152. serializer.save(user=self.request.user)

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

文件“/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py”在 创建 67. images_data = 已验证_data.pop('images')

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

【问题讨论】:

【参考方案1】:

问题描述

异常的起源是KeyError,因为这个声明

images_data = validated_data.pop('images')

这是因为经过验证的数据没有密钥 images。这意味着图像输入不会验证来自邮递员的图像输入。

Django 发布请求将InMemmoryUpload 存储在request.FILES 中,因此我们使用它来获取文件。此外,您希望一次上传多张图片。因此,在上传图片时(在邮递员中),您必须使用不同的 image_names。

把你的serializer改成这样:

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

我不知道你的观点,但我想使用ModelViewSet首选视图类

class Upload(ModelViewSet):
    serializer_class = TaskSerializer
    queryset = Task.objects.all()

邮递员控制台:

DRF 结果:


        "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"
            
        ]
    

更新

这是您评论的答案。

在 django 中,reverse foreignKey 正在使用 _set 进行捕获。看到这个official doc。这里TaskTaskImageOneToMany 关系,所以如果你有一个Task 实例,你可以通过reverse look-up 特性获取所有相关的TaskImage 实例。

示例如下:

task_instance = Task.objects.get(id=1)
task_img_set_all = task_instance.taskimage_set.all()

这里task_img_set_all 将等于TaskImage.objects.filter(task_id=1)

【讨论】:

如果你想要bitbucket.org/jerinpetergeorge/django_1_11/src/…,你可以使用这个 git-repo 谢谢,这是完美的。我注意到在serializers 你使用source=taskimage_set,我不知道为什么会这样?使用task_image_set 或更一般的model-field_set 是有意义的,这只是用于一对多关系的约定吗? 请查看答案底部的 UPDATE 部分, 创建TaskImage(TaskImage.objects.create(task=task, image=image_data))时,不应该用序列化器创建吗?如果不这样做,我会假设您正在绕过验证阶段,并在没有验证的情况下保存对象? 并非如此,因为图像已针对 serializer.ImageField() 字段进行验证【参考方案2】:

您已在 TaskImageSerializer 嵌套字段中将 read_only 设置为 true。所以那里不会有validated_data。

【讨论】:

我删除了,但是错误和回溯还是一样

以上是关于Django REST:上传和序列化多个图像的主要内容,如果未能解决你的问题,请参考以下文章

django rest框架在序列化程序创建方法中获取请求

django-rest-framework 序列化器在多个视图中的不同字段

1个模型的django-rest-framework多个序列化器?

Django.rest_framework:如何序列化一对多?

即使在创建帖子期间使用 Postman 将文件上传到该字段后,Django Rest Framework 仍显示字段错误

如何使用 DJango Rest Framework 上传多个图像?