保存相关图像Django REST框架

时间:2017-06-27 13:39:52

标签: python django django-rest-framework

我有这个基本的模型布局:

class Listing(models.Model):
    name = models.TextField()

class ListingImage(models.Model):
    listing = models.ForeignKey(Listing, related_name='images', on_delete=models.CASCADE)
    image = models.ImageField(upload_to=listing_image_path)

我正在尝试编写一个序列化程序,它允许我添加一个rest api端点来创建包含图像的列表。

我的想法是:

class ListingImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ListingImage
        fields = ('image',)

class ListingSerializer(serializers.ModelSerializer):
    images = ListingImageSerializer(many=True)

class Meta:
    model = Listing
    fields = ('name', 'images')

def create(self, validated_data):
    images_data = validated_data.pop('images')
    listing = Listing.objects.create(**validated_data)
    for image_data in images_data:
        ListingImage.objects.create(listing=listing, **image_data)

    return listing

我的问题是:

  1. 我不确定如何使用多部分POST请求在嵌套词典中发送图像列表。

  2. 如果我只是在调用序列化程序之前发布图像列表并尝试将其从列表转换为字典列表,则在解析实际图像时会出现奇怪的操作系统错误。

    for key, item in request.data.items():
        if key.startswith('images'):
            # images.append({'image': item})
            request.data[key] = {'image': item}
    
  3. 我的请求代码如下所示:

    import requests
    from requests_toolbelt.multipart.encoder import MultipartEncoder
    
    api_token = 'xxxx'
    
    images_data = MultipartEncoder(
        fields={
            'name': 'test',
            'images[0]': (open('lilo.png', 'rb'), 'image/png'),
            'images[1]': (open('panda.jpg', 'rb'), 'image/jpeg')
        }
    )
    
    
    response = requests.post('http://127.0.0.1:8000/api/listings/', data=images_data,
                             headers={
                                 'Content-Type': images_data.content_type,
                                 'Authorization': 'Token' + ' ' + api_token
                             })
    

    我确实找到了一个非常hacky的解决方案,我将在答案中发布,但它不是很强大,需要有更好的方法来实现这一点。

1 个答案:

答案 0 :(得分:2)

所以我的解决方案是基于这篇文章而且效果很好,但看起来非常不稳定和hacky。

我将图像字段从需要dictonary的关系序列化器更改为ListField。这样做我需要覆盖列表字段方法,以便在调用" to_repesentation"时实际从RelatedModelManager创建一个List。

这个字符在输入上表现得像一个列表,但就像读取的模板文件一样。

class ModelListField(serializers.ListField):
    def to_representation(self, data):
        """
        List of object instances -> List of dicts of primitive datatypes.
        """
        return [self.child.to_representation(item) if item is not None else None for item in data.all()]


class ListingSerializer(serializers.ModelSerializer):
    images = ModelListField(child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False))

    class Meta:
        model = Listing
        fields = ('name', 'images')

    def create(self, validated_data):
        images_data = validated_data.pop('images')
        listing = Listing.objects.create(**validated_data)
        for image_data in images_data:
            ListingImage.objects.create(listing=listing, image=image_data)

        return listing
相关问题