首页 文章

保存相关图像Django REST Framework

提问于
浏览
3

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

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 endpoints 来创建包含图像的列表 .

我的想法是这样的:

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

我的问题是:

  • 我不知道如何使用多部分POST请求在嵌套字典中发送图像列表 .

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

for key, item in request.data.items():
    if key.startswith('images'):
        # images.append({'image': item})
        request.data[key] = {'image': item}

我的请求代码如下所示:

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 回答

  • 2

    所以我的解决方案是基于这篇文章,并且工作得很好,但看起来非常不稳定和hacky .

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

    这个baiscally行为类似于输入列表,但就像读取时的模板文件 .

    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
    

相关问题