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.
相关产品推荐
相关产品推荐

