本文介绍了Django REST:上传和序列化多个图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have 2 models Task and TaskImage which is a collection of images belonging to Task object.

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

What I want is to be able to add multiple images to my Task object, but I can only do it using 2 models. Currently, when I add images, it doesn't let me upload them and save new objects.

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)

但是,当我执行发布请求时:

However, when I do a post request:

我得到以下回溯:

File
/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)

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py" in _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 = wrapd_callback(request,* callback_args,** callback_kwargs)

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

File
/ Applications / Anaconda / anaconda / envs / godo / lib / python3。 6 / site-packages / django / views / decorators / csrf.py
in wrapd_view
58. return view_func(* args,** kwargs)

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/views/decorators/csrf.py" in 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(请求,* args, ** kwargs)

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py" in view 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)

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in dispatch 494. response = self.handle_exception(exc)

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

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

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

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in dispatch 491. response = handler(request, *args, **kwargs)

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

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py" in create 21. self.perform_create(serializer)

文件​​ / Users / gr / Desktop /pycharmProjects/godo/api/views.py在
perform_create
152中。序列化r.save(user = self.request.user)

File "/Users/gr/Desktop/PycharmProjects/godo/api/views.py" in 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)

File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/serializers.py" in save 214. self.instance = self.create(validated_data)

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

File "/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py" in create 67. images_data = validated_data.pop('images')

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

Exception Type: KeyError at /api/tasks/ Exception Value: 'images'


推荐答案

问题描述

异常的起源是 KeyError ,由于此语句

The origin of the exception was a KeyError, because of this statement

images_data = validated_data.pop('images')

这是因为已验证的数据没有密钥图像

This is because the validated data has no key images. This means the images input doesn't validate the image inputs from postman.

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

Django post request store InMemmoryUpload in request.FILES, so we use it for fetching files. also, you want multiple image upload at once. So, you have to use different image_names while your image upload (in postman).

将您的序列化器更改为喜欢

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

我不知道您的看法,但我想使用 ModelVi ewSet 首选视图类

I don't know about your view, but I'd like to use ModelViewSet preferrable view class

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 捕获。请参阅此。在这里, Task TaskImage 处于 OneToMany 关系,所以如果您有一个 Task 实例,则可以通过此反向外观获得所有相关的 TaskImage 实例-up 功能。

In django reverse foreignKey are capturing using _set. see this official doc. Here, Task and TaskImage are in OneToMany relationship, so if you have one Task instance, you could get all related TaskImage instance by this reverse look-up feature.

这里是示例:

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)

这篇关于Django REST:上传和序列化多个图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 07:00