Django应用中使用WeasyPrint渲染PDF时自定义字体无法加载
解决WeasyPrint在Django中无法加载自定义字体的问题
问题描述
生成PDF时出现错误:
fonts/add_font_face - Font-face 'Playfair Display' cannot be loaded
项目目录结构:
- project - manage.py - ... - gallery - static - files # 注意:模板中引用的是fonts目录,此处可能存在目录名不一致问题 - views.py - url.py - ...
生成PDF的代码:
base_url = request.build_absolute_uri("/") HTML(string=template, base_url=base_url).write_pdf(output)
模板中的@font-face定义:
@font-face { font-family: 'Playfair Display'; font-weight: normal; src: url({% static 'fonts/PlayfairDisplay-Regular.ttf' %}) format("truetype"); }
解决建议
1. 核对静态文件目录与路径
- 检查
gallery/static下是否存在fonts目录:当前目录结构显示的是static/files,与模板中引用的fonts目录不匹配,这很可能是核心问题。如果是目录名写错,将files重命名为fonts,或者调整模板中的路径为files/PlayfairDisplay-Regular.ttf。 - 执行
python manage.py collectstatic:确保静态文件被收集到Django配置的STATIC_ROOT目录下,WeasyPrint在访问静态资源时通常依赖收集后的文件(尤其是生产环境)。
2. 优化base_url参数配置
- 替换base_url为静态文件的绝对根路径:
这样WeasyPrint能更精准地解析from django.conf import settings base_url = request.build_absolute_uri(settings.STATIC_URL)static标签生成的相对路径。 - 或者直接在模板中生成绝对路径:
修改@font-face的src为绝对URL,无需依赖base_url:src: url("{{ request.build_absolute_uri('/static/fonts/PlayfairDisplay-Regular.ttf') }}") format("truetype");
3. 直接使用本地文件路径加载字体
绕过静态文件服务,直接传入字体文件的本地绝对路径给WeasyPrint:
- 在视图中拼接字体文件的本地路径:
import os from django.conf import settings font_path = os.path.join(settings.STATICFILES_DIRS[0], 'fonts', 'PlayfairDisplay-Regular.ttf') - 将该路径传入模板上下文,在@font-face中使用:
注意:src: url("file://{{ font_path }}") format("truetype");file://前缀是WeasyPrint识别本地文件的关键。
4. 检查文件权限与字体有效性
- 确保字体文件的读取权限:在Linux/macOS环境下,执行
chmod 644 /path/to/gallery/static/fonts/PlayfairDisplay-Regular.ttf,赋予进程读取权限。 - 验证字体文件完整性:尝试用系统字体查看器打开字体文件,确认是未损坏的TrueType格式文件;同时检查文件名大小写(Linux系统大小写敏感)是否与模板中完全一致。
5. 调整@font-face的定义细节
- 补充必要的字体属性,避免解析歧义:
@font-face { font-family: 'Playfair Display'; font-weight: normal; font-style: normal; src: url({% static 'fonts/PlayfairDisplay-Regular.ttf' %}) format("truetype"); font-display: swap; }
内容的提问来源于stack exchange,提问作者charliesneath
相关产品推荐
相关产品推荐

