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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:38:11