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

Django REST: Uploading and serializing multiple images

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

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

设置.py

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

序列化程序.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

型号.py

1
2
3
4
5
6
7
8
9
10
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)

但是,当我执行post请求时:

enter image description here

我得到了以下回溯:

File
"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/exception.py"
in inner
41. response = get_response(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)

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 wrapped_view
58. return view_func(*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)

File
"/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py"
in dispatch
494. response = self.handle_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)

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

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

File"/Users/gr/Desktop/PycharmProjects/godo/api/views.py" in
perform_create
152. serializer.save(user=self.request.user)

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

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

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


问题描述例外的起源是一个KeyError,因为这个声明images_data = validated_data.pop('images')。这是因为验证的数据没有密钥images。这意味着图像输入不会验证来自邮递员的图像输入。Django Post请求将InMemmoryUpload存储在request.FILES中,因此我们使用它来获取文件。另外,您希望一次上载多个图像。所以,在上传图片时,你必须使用不同的图片名(邮差)。把你的serializer改成这样,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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预科课程

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

邮差控制台enter image description here。DRF结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
       "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捕获。见官方文件。这里,TaskTaskImageOneToMany关系,所以如果你有一个Task实例,你可以通过这个reverse look-up特性得到所有相关的TaskImage实例。下面是例子

1
2
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)


TaskImageSerializer嵌套字段中,已将read_only设置为true。所以那里没有经过验证的数据。