You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中WebP转换失败生成空Picture元素,调试无果求助

多图片上传转WebP后生成空Picture元素问题分析

我正在开发一个多图片上传表单,需要将上传图片转换为WebP格式。原本功能正常,但添加WebP转换逻辑后出现问题:无任何异常抛出,服务器日志显示执行成功,却在数据库中生成空的Picture元素。使用的技术栈为Django Cookiecutter项目及Pillow库。

更新:已解决的代码

对解决方案做少量修改后,问题成功解决:

class GalleryView(APIView):
  parser_class = (FileUploadParser,)

  def post(self, request):
    # Extract the facility ID and list of pictures from the request
    print('post method called')
    facility_id = request.data.get('facility')
    pictures = request.data.getlist('pictures')

    print(facility_id, pictures)

    facility = get_object_or_404(Facility, id=facility_id)

    try:
      gallery = Gallery.objects.get(facility=facility)
    except Gallery.DoesNotExist:
      gallery = Gallery.objects.create(facility=facility)

    with transaction.atomic():
        for picture in pictures:
            print('for loop executing')
            try:
                webp_image = BytesIO()
                image = Image.open(picture)
                image.save(webp_image, format='webp', quality=5)
                print(webp_image)
                
                file_name = picture.name
                if picture.name.lower().endswith(('.jpg', '.jpeg', '.png')):
                    file_name = f"{os.path.splitext(picture.name)[0]}.webp"
                else:
                    file_name = picture.name
                file_object = ContentFile(webp_image.getvalue(), name=file_name)
                print(file_object)
                picture_obj = Picture.objects.create(picture=file_object)
                print(picture_obj)
                gallery.pictures.add(picture_obj)
                print(gallery)
            except Exception as e:
                print(type(e))
                continue

    serializer = GallerySerializer(gallery)
    return Response(serializer.data, status=201)

问题出现时的相关代码

models.py

def upload_gallery_image(instance, filename):
  # Print a message to indicate that the function was called
  print(instance, filename)
  return f'galleries/{instance.facility.id}/{filename}'


class Picture(models.Model):
  picture = models.ImageField(upload_to=upload_gallery_image)
  
class Gallery(models.Model):
  facility = models.ForeignKey(Facility, on_delete=models.CASCADE, related_name='tourphotos')
  pictures = models.ManyToManyField(Picture, related_name='galleries')

views.py

class GalleryView(APIView):
  parser_class = (FileUploadParser,)

  def post(self, request):
    # Extract the facility ID and list of pictures from the request
    print('post method called')
    facility_id = request.data.get('facility')
    pictures = request.data.getlist('pictures')

    print(facility_id, pictures)

    facility = get_object_or_404(Facility, id=facility_id)

    try:
      gallery = Gallery.objects.get(facility=facility)
    except Gallery.DoesNotExist:
      gallery = Gallery.objects.create(facility=facility)

    for picture in pictures:
        print('for loop executing')
        try:
            webp_image = BytesIO()
            image = Image.open(picture)
            image.save(webp_image, format='webp', quality=75)
            print(webp_image)
            file_object = ContentFile(webp_image.getvalue())
            print(file_object)
            picture_obj = Picture.objects.create(picture=file_object)
            print(picture_obj)
            gallery.pictures.add(picture_obj)
            print(gallery)
        except Exception as e:
            print(type(e))
            continue

    webp_image.close()

    serializer = GallerySerializer(gallery)
    return Response(serializer.data, status=201)

serializers.py

class PictureSerializer(serializers.ModelSerializer):
    class Meta:
        model = Picture
        fields = ('id', 'picture')

class GallerySerializer(serializers.ModelSerializer):
    pictures = PictureSerializer(many=True)
    class Meta:
        model = Gallery
        fields = ('id', 'pictures')

服务器响应日志

django          | post method called
django          | 24 [<InMemoryUploadedFile: 156f9f885e468c60dd7d6d539f2ee1bb.webp (image/webp)>]
django          | for loop executing
django          | <_io.BytesIO object at 0x7fbfdb14eef0>
django          | Raw content
django          | Picture object (304)
django          | Gallery object (59)
django          | 172.21.0.1 - - [02/Jan/2023 11:09:44] "POST /api/multipleupload/ HTTP/1.1" 201 -

问题原因

  1. 缺少文件名参数:原代码中创建ContentFile时仅传入了文件内容,未指定文件名:

    file_object = ContentFile(webp_image.getvalue())
    

    Django的ImageField依赖文件名来确定存储路径(对应upload_to函数的filename参数)和文件格式标识,缺少文件名会导致Django无法正确处理文件存储逻辑,最终数据库中仅生成空的Picture记录,无实际文件关联。

  2. 事务缺失(次要):原代码未使用事务包裹批量创建逻辑,若中途出现异常可能导致部分数据残留,但结合日志来看,本次问题的核心还是文件名缺失。

内容的提问来源于stack exchange,提问作者Matthias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:15:32