栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在Django REST Framework中使用multipart / form-data上传多个图像和嵌套的json

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在Django REST Framework中使用multipart / form-data上传多个图像和嵌套的json

我开发了一个解决方案。使用邮递员,我发送了包含多个图像,单个和嵌套数据的multipart / form-data。

在我的模型文件中,我将Tags模型添加为ManyToManyField作为示例,并添加了django-taggit。 表单数据 将如图所示。

models.py

class Product(models.Model):    name = models.CharField(max_length=20, blank=True)    tags = models.ManyToManyField(Tags)    taggit = TaggableManager(blank=True)class ProductImage(models.Model):    product = models.ForeignKey(Product, on_delete=models.CASCADE)    image = models.ImageField(upload_to='image_path/', null=True, blank=True)class Tags(models.Model):    name = models.CharField(max_length=15, blank=True)

首先是第一件事;第一个数据未正确解析。为了解决这个问题,并借助该答案,我创建了这个自定义 解析器

class MultipartJsonParser(parsers.MultiPartParser):    def parse(self, stream, media_type=None, parser_context=None):        result = super().parse( stream, media_type=media_type, parser_context=parser_context        )        data = {}        for key, value in result.data.items(): if type(value) != str:     data[key] = value     continue if '{' in value or "[" in value:     try:         data[key] = json.loads(value)     except ValueError:         data[key] = value else:     data[key] = value        return parsers.DataAndFiles(data, result.files)

现在,我们可以使用此解析器和Django REST内置JSONParser解析数据。现在该建立我们的 视图集了

class ProductViewSet(ModelViewSet):    queryset = Product.objects.all()    serializer_class = ProductSerializer    parser_classes = [MultipartJsonParser, JSONParser]    def get_serializer_context(self):        context = super(ProductViewSet, self).get_serializer_context()        # appending extra data to context        if len(self.request.FILES) > 0: context.update({     'included_images': self.request.FILES })        return context    def create(self, request, *args, **kwargs):        # Validating images with its own serializer, but not creating.        # The adding process must be through Serializer.        try: image_serializer = ProductImageSerializer(data=request.FILES) image_serializer.is_valid(raise_exception=True)        except Exception: raise NotAcceptable(     detail={         'message': 'Upload a valid image. The file you uploaded was either not '         'an image or a corrupted image.'}, pre=406)        # the rest of method is about the product serialization(with extra context),         # validation and creation.        serializer = self.get_serializer(data=request.data)        serializer.is_valid(raise_exception=True)        self.perform_create(serializer)        headers = self.get_success_headers(serializer.data)        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)class ProductImageViewSet(ModelViewSet):    queryset = ProductImage.objects.all()    serializer_class = ProductImageSerializerclass TagsViewSet(ModelViewSet):    queryset = Tags.objects.all()    serializer_class = TagsSerializer

让我们在这里检查。正如我在评论中提到的,图像文件将包含在request.FILES中。因此,我首先将数据发送到
ProductImageSerializer

并进行了验证。如果发生验证错误,该过程将停止,API将发送一条错误消息作为响应。然后,我将数据发送到ProductSerializer,并将图片信息附加到
get_serializer_context 方法中的上下文中。

我们已经完成了 create 方法,其他细节都写在了代码上。

最后, serializer.py

from django.forms import ImageField as DjangoImageFieldclass TagsSerializer(HyperlinkedModelSerializer):    class meta:    model = Tags    fields = ['url', 'pk', 'name']class ProductImageSerializer(HyperlinkedModelSerializer):    class meta:        model = ProductImage        fields = ['url', 'pk', 'product', 'image']        # attention!!! if you not use this bottom line,        # it will show error like "product required" and        # indirectly our validation at ProductViewSet will raise error.        extra_kwargs = { 'product': {'required': False}        }    # we created Object-level custom validation because validation not working correctly.    # when ProductImageSerializer get single image, everything just fine but    # when it get multiple image, serializer is just passing all the files.    def validate(self, attrs):        default_error_messages = { 'invalid_image':     'Upload a valid image. The file you uploaded was either not an image or a corrupted image.',        }        # in here we're verifying image with using django.forms; Pillow not necessary !!        for i in self.initial_data.getlist('image'): django_field = DjangoImageField() django_field.error_messages = default_error_messages django_field.clean(i)        return attrsclass ProductSerializer(HyperlinkedModelSerializer, TaggitSerializer):    tags = TagsSerializer(allow_null=True, many=True, required=False)    # you can delete this line. If you delete it, it will appear as url in response.    productimage_set = ProductImageSerializer(allow_null=True, many=True, required=False)    taggit = TagListSerializerField(allow_null=True, required=False)    class meta:        model = Product        fields = ['url', 'pk', 'name', 'tags', 'taggit', 'productimage_set']    def create(self, validated_data):        # create product        try: product_obj = Product.objects.create(     name=validated_data['name'] )        except Exception: raise NotAcceptable(detail={'message': 'The request is not acceptable.'}, pre=406)        if 'included_images' in self.context:  # checking if key is in context images_data = self.context['included_images'] for i in images_data.getlist('image'):     ProductImage.objects.create(         product=product_obj,         image=i     )        # pop taggit and create        if 'taggit' in validated_data: taggit_data = validated_data.pop('taggit') for taggit_data in taggit_data:     taggit_obj, created = Tag.objects.get_or_create(name=taggit_data)     product_obj.taggit.add(taggit_obj)        # pop tags and create        if 'tags' in validated_data: tags_data = validated_data.pop('tags') for tags_data in tags_data:     for i in tags_data.items():         tags_obj, created = Tags.objects.get_or_create(name=i[1])         product_obj.tags.add(tags_obj)        return product_obj

那么这里发生了什么?为什么我们要为图像创建额外的验证?尽管我不知道为什么,但是ImageSerializer仅对单个文件进行正确的验证。如果您尝试上传两个文件,甚至可以在图片旁边放一个电影,验证将无法进行。为了防止这种情况,我们使用django的内置形式依次验证了图片;更改.mp3的格式并将其设置为.jpg,尝试上传高尺寸的文件,但它们均不起作用。进行验证的是纯django。其他细节在代码中。

如果您按照我说的去做,那么响应将是这样的:

我认为这会使大多数 Postman 用户满意。希望对您有所帮助。如果有什么引起您的注意,让我们见面。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/648974.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号