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

Django中xhtml2pdf生成PDF时图片无法加载,求解决方案

Django + xhtml2pdf 图片无法显示问题解决方案

核心问题原因

xhtml2pdf在服务器端生成PDF时,无法直接通过HTTP相对URL访问图片,需要本地文件系统的绝对路径,或者通过回调函数将URL映射到本地文件路径。而Django网页中使用的url属性是HTTP访问路径,不符合xhtml2pdf的处理逻辑。

具体解决方法

1. 直接传递本地文件绝对路径到模板

在视图中为每个Reserva对象添加本地文件路径属性,模板直接使用该路径:

修改视图代码:

from django.conf import settings
import os

def DescargarReserva(request, id):
    reservas = Reserva.objects.filter(idSolicitud=id)
    # 为每个reserva添加本地图片路径
    for reserva in reservas:
        reserva.imagen_carnet_local_path = os.path.join(settings.MEDIA_ROOT, reserva.ImagenCarnet.name)
    Orden = Reserva()
    data = {'reservas': reservas, 'Orden': Orden}
    pdf_response = genpdf('templatesApp/pdf.html', data)
    if pdf_response:
        response = HttpResponse(pdf_response, content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="reserva.pdf"'
        return response
    return HttpResponse("Error al generar el PDF", status=500)

修改模板代码:

<img src="{{ reserva.imagen_carnet_local_path }}" style="max-width: 300px; max-height: 200px;" />

2. 配置xhtml2pdf的链接回调函数

通过link_callback参数让xhtml2pdf自动将HTTP URL转换为本地文件路径,无需修改模板:

定义回调函数并修改genpdf函数:

def link_callback(uri, rel):
    from django.conf import settings
    import os
    # 处理媒体文件URL
    if uri.startswith(settings.MEDIA_URL):
        path = os.path.join(settings.MEDIA_ROOT, uri.replace(settings.MEDIA_URL, ''))
    elif uri.startswith(settings.STATIC_URL):
        # 处理静态文件(若需要)
        path = os.path.join(settings.STATIC_ROOT, uri.replace(settings.STATIC_URL, ''))
    else:
        return uri
    # 验证文件存在
    if not os.path.isfile(path):
        raise ValueError(f"No se encontró el archivo: {path}")
    return path

def genpdf(template_path, context):
    from django.template.loader import get_template
    from xhtml2pdf import pisa
    from io import BytesIO
    
    template = get_template(template_path)
    html = template.render(context)
    result = BytesIO()
    # 生成PDF时传入回调函数
    pdf = pisa.CreatePDF(html, dest=result, link_callback=link_callback)
    if not pdf.err:
        return result.getvalue()
    return None

模板保持原有代码即可:

<img src="{{ reserva.ImagenCarnet.url }}" style="max-width: 300px; max-height: 200px;" />

3. 修正模型中的细节错误

  • 模型类名拼写错误:models.model → models.Model
  • 默认图片路径确保在MEDIA_ROOT范围内:将default='App/carnets/example.jpg'改为default='images/example.jpg'(与upload_to='images/'对应)

修正后的模型代码:

class Reserva(models.Model):
    ImagenCarnet = models.ImageField(upload_to='images/', default='images/example.jpg')

4. 验证文件路径正确性

在视图中打印图片实际路径,确认文件存在:

for reserva in reservas:
    print(reserva.ImagenCarnet.path)  # 检查输出路径是否存在对应图片

额外注意事项

  • 生产环境中确保MEDIA_ROOT目录权限正确,服务器进程有读取权限
  • 若使用S3等云存储,需修改link_callback函数,通过云存储API获取文件字节流传入xhtml2pdf

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:26:09