如何用Django BinaryField在PostgreSQL存储PNG并正常显示
问题解决:BinaryField存储PNG二进制后转base64无法显示的问题
核心原因
模板渲染时,Django默认会对变量进行HTML转义,base64字符串中的特殊字符(如+、/、=)会被替换为HTML实体(比如+变成+),导致生成的data URI无效。
解决方案
方案1:模板中使用safe过滤器
直接在模板变量后添加|safe,告诉Django不要转义该字符串:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <pre>data:image/png;base64,{{ data|safe }}</pre> <img src="data:image/png;base64,{{ data|safe }}" alt="" /> </body> </html>
方案2:视图中标记数据为安全
使用Django的mark_safe函数提前标记base64字符串为安全内容,避免模板转义:
from django.utils.safestring import mark_safe import base64 from django.http import HttpRequest from django.shortcuts import render from .models import ImageFile def image_view(request: HttpRequest, id: int): document_file = ImageFile.objects.filter(id=id).first() data = "" if document_file: base64_str = base64.b64encode(document_file.file).decode(encoding="ascii") data = mark_safe(base64_str) return render(request, "image.html", {"data": data})
额外验证:确保存储的二进制数据正确
可以在视图中打印存储的二进制数据的文件头,确认是完整的PNG数据(PNG文件头为b'\x89PNG\r\n\x1a\n'):
if document_file: print(document_file.file[:8]) # 应输出 b'\x89PNG\r\n\x1a'
实现图片压缩(满足你的压缩需求)
如果需要在存储前压缩图片,修改自定义Widget的value_from_datadict方法,使用Pillow处理图片:
from PIL import Image import io from django import forms class BinaryFileInputWidget(forms.ClearableFileInput): def is_initial(self, value): return bool(value) def format_value(self, value): if self.is_initial(value): return f"{len(value)} bytes" def value_from_datadict(self, data, files, name): upload = super().value_from_datadict(data, files, name) if upload: # 打开图片并压缩 with Image.open(upload) as img: output = io.BytesIO() # PNG压缩参数:optimize开启优化,quality控制质量(1-100) img.save(output, format='PNG', optimize=True, quality=80) output.seek(0) return output.read()
这样既可以存储压缩后的二进制数据,又能保证后续转base64后正常展示。
内容的提问来源于stack exchange,提问作者Sadra Saderi
相关产品推荐
相关产品推荐

