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

Django上传JPEG图片触发AttributeError错误求助

Django上传JPEG图片触发500错误(PNG正常)

错误日志

Internal Server Error: /publish_offer/
Traceback (most recent call last):
  File "C:\Users\G-FIVE\Desktop\Projects\revenue\venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\G-FIVE\Desktop\Projects\revenue\venv\Lib\site-packages\django\utils\deprecation.py", line 136, in __call__
    response = self.process_response(request, response)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\G-FIVE\Desktop\Projects\revenue\venv\Lib\site-packages\django\middleware\clickjacking.py", line 27, in process_response
    if response.get("X-Frame-Options") is not None:
       ^^^^^^^^^^^^
AttributeError: 'SafeString' object has no attribute 'get'
[19/Jun/2023 14:08:35] "POST /publish_offer/ HTTP/1.1" 500 66377

相关代码

模型代码

class ImagenesOferta(models.Model):
    imagen = models.ImageField(verbose_name='Imagen Oferta', blank=False, null=False, upload_to='img_ofertas/')

    class Meta:
        verbose_name = 'Imagen de Oferta'
        verbose_name_plural = 'Imagenes de Ofertas'
        ordering = ['-id']

class Oferta(models.Model):
    titulo = models.CharField(verbose_name='Título', max_length=100, null=False, blank=False)
    descripcion = models.TextField(verbose_name='Descripción', null=True, blank=True)
    cantidad = models.PositiveSmallIntegerField(verbose_name='Cantidad', null=False, blank=False, default=1)
    valor = models.DecimalField(verbose_name='Valor', max_digits=3, decimal_places=2, null=False, blank=False)
    material = models.CharField(verbose_name='Material', max_length=20, null=False, blank=False, choices=MATERIAL_CHOICES)
    imagenes = models.ManyToManyField(ImagenesOferta, verbose_name='Imagenes de la Oferta', blank=True)
    usuario = models.ForeignKey(Usuario, verbose_name='Usuario', null=False, blank=False, on_delete=models.CASCADE)
    is_active = models.BooleanField(verbose_name='Activo/Inactivo', default=True)
    vendido = models.BooleanField(verbose_name='Vendido', default=False)
    fecha_creacion = models.DateTimeField(verbose_name='Fecha de Creación', auto_now_add=True)

    def __str__(self):
        return self.titulo

    class Meta:
        verbose_name = 'Oferta'
        verbose_name_plural = 'Ofertas',
        ordering = ['-fecha_creacion']

视图代码

@login_required(login_url='login')
def publish_offer(request):

    form = formOferta()

    if request.method == 'POST':
        form = formOferta(request.POST, request.FILES)
        if form.is_valid():
            form.instance.usuario = request.user
            oferta = form.save()
            imgs = [
                ImagenesOferta(imagen=image)
                for image in request.FILES.getlist('imagenes')
            ]
            ImagenesOferta.objects.bulk_create(imgs)
            oferta.imagenes.add(*imgs)
            return redirect('home')
        else:
            return form.errors
        
    return render(request, 'publicar_oferta.html', {
        'form': form
    })

模板上传输入框

<div class="mb-3">
    <h5 class="text-center my-4">Añade Imagenes</h5>
    <label for="imagenes" class="form-label">Cargar Imagenes</label>
    <input class="form-control-file" type="file" id="imagenes" name="imagenes" multiple>
</div>

问题原因

  1. 视图返回值类型错误:表单验证失败时,视图直接返回form.errors,这是SafeString对象,而非Django要求的HttpResponse子类。中间件处理响应时调用response.get()方法,因对象类型不匹配触发AttributeError。
  2. JPEG验证失败触发错误分支:PNG能正常上传说明流程逻辑无问题,但JPEG可能因缺少图片处理依赖(如Pillow)导致表单验证不通过,进入错误分支触发上述异常。

解决方案

1. 修正视图错误返回逻辑

删除else分支的return form.errors,让验证失败时自动执行到下方的render,模板会自动渲染表单错误信息:

@login_required(login_url='login')
def publish_offer(request):
    form = formOferta()
    if request.method == 'POST':
        form = formOferta(request.POST, request.FILES)
        if form.is_valid():
            form.instance.usuario = request.user
            oferta = form.save()
            imgs = [
                ImagenesOferta(imagen=image)
                for image in request.FILES.getlist('imagenes')
            ]
            ImagenesOferta.objects.bulk_create(imgs)
            oferta.imagenes.add(*imgs)
            return redirect('home')
    # 无论验证成功或失败,都渲染模板
    return render(request, 'publicar_oferta.html', {
        'form': form
    })

2. 安装图片处理依赖

Django的ImageField依赖Pillow处理图片格式验证,执行以下命令安装:

pip install pillow

3. 可选:添加图片格式验证

在formOferta中显式限制图片格式,避免非允许格式的图片提交:

from django import forms
from .models import Oferta

class formOferta(forms.ModelForm):
    class Meta:
        model = Oferta
        fields = ['titulo', 'descripcion', 'cantidad', 'valor', 'material']

    def clean_imagenes(self):
        images = self.files.getlist('imagenes')
        allowed_types = ['image/jpeg', 'image/png']
        for img in images:
            if img.content_type not in allowed_types:
                raise forms.ValidationError("仅支持JPEG和PNG格式图片")
        return images

内容的提问来源于stack exchange,提问作者Angel Daniel Ascanio Salazar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:05:21