Django集成Weasyprint生成PDF无法加载静态资源报错问询
问题根因
你自定义的url_fetcher仅对file://协议开头的资源生效,但你在初始化HTML对象时传入了base_url=request.build_absolute_uri("/"),导致模板渲染后的静态资源地址为完整的HTTP地址(如http://api.dashboard.localhost:8000/static/logos/logo.png),不会触发你写的本地文件读取逻辑,直接走WeasyPrint默认的网络请求逻辑。而你的Docker容器内部没有配置api.dashboard.localhost的hosts映射,所以发起网络请求时会出现域名解析失败的报错。
解决方案
方案1:修改url_fetcher适配HTTP协议的本站静态资源(推荐)
调整url_fetcher的判断逻辑,不管资源是http/https还是file协议,只要路径符合静态/媒体资源的前缀规则,就直接从本地读取:
def url_fetcher(url, *args, **kwargs): parsed_url = urlparse(url) url_path = parsed_url.path # 处理媒体资源 default_media_url = settings.MEDIA_URL in ('', get_script_prefix()) if not default_media_url and url_path.startswith(settings.MEDIA_URL): mime_type, encoding = mimetypes.guess_type(url) media_root = settings.MEDIA_ROOT if isinstance(settings.MEDIA_ROOT, Path): media_root = f'{settings.MEDIA_ROOT}/' path = url_path.replace(settings.MEDIA_URL, media_root, 1) return { 'mime_type': mime_type, 'encoding': encoding, 'filename': Path(url_path).name, 'file_obj': default_storage.open(path) } # 处理静态资源 elif settings.STATIC_URL and url_path.startswith(settings.STATIC_URL): mime_type, encoding = mimetypes.guess_type(url) path = url_path.replace(settings.STATIC_URL, '', 1) return { 'mime_type': mime_type, 'encoding': encoding, 'filename': Path(url_path).name, 'file_obj': open(find(path), 'rb') } # 外部资源走默认请求逻辑 return weasyprint.default_url_fetcher(url, *args, **kwargs)
方案2:修改base_url为本地协议
初始化HTML对象时不传入HTTP协议的base_url,直接使用file://协议指向项目根目录,适配原有url_fetcher逻辑:
HTML( string=template_string, base_url=f'file://{settings.BASE_DIR}/', url_fetcher=url_fetcher ).write_pdf(results)
方案3:Docker容器配置hosts映射
如果确实需要走网络请求获取资源,可以在Docker运行配置中添加hosts映射,将域名指向本机:
- docker运行命令添加参数:
docker run --add-host api.dashboard.localhost:127.0.0.1 <其余运行参数> - docker-compose配置添加字段:
services: 你的服务名: extra_hosts: - "api.dashboard.localhost:127.0.0.1"
额外检查项
- 模板中引用的是
logos/logo.jpg,报错信息中显示的是logo.png,请确认静态目录下的文件后缀是否匹配,避免文件不存在的问题 - 生产环境部署后请确认已执行
collectstatic命令,保证find()方法可以正常找到对应的静态文件
内容的提问来源于stack exchange,提问作者coredumped0x
相关产品推荐
相关产品推荐

