如何使用Django BinaryField在postgres中存储PNG图像?

问题描述 投票:0回答:1

我需要将 PNG 文件作为 blob/二进制存储在数据库中,然后能够检索并显示它们。

这是我的模型,它有一个二进制字段来存储图像:

class ImageFile(models.Model):
    file = models.BinaryField(editable=True)

我根据这个答案创建了一个小部件:

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:
            return upload.read()

我在

admin.py
中使用它,如下所示:

@admin.register(ImageFile)
class ImageFileAdmin(admin.ModelAdmin):
    list_display = ["id"]
    formfield_overrides = {
        models.BinaryField: {"widget": BinaryFileInputWidget()},
    }

然后我在视图中将文件编码为

base64

def image_view(request: HttpRequest, id: int):
    document_file = ImageFile.objects.filter(id=id).first()
    data = ""
    if document_file:
        data = base64.b64encode(document_file.file).decode(encoding="ascii")
    return render(request, "image.html", {"data": data})
<!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 }}</pre>
    <img src="data:image/png;base64,{{ data }}" alt="" />
  </body>
</html>

没有错误,数据显示在

pre
元素中,但
img
元素无法加载图像。我尝试使用一些在线转换器来检查数据是否有效,但它们显示错误,指出 base64 字符串无效。

如果我在将文件存储在数据库中之前将文件转换为小部件中的

base64
return base64.b64encode(upload.read()).decode('ascii')
而不是
return upload.read()
),然后在视图中再次转换,它会正确加载。但我不能使用这种方法,因为我可能需要压缩文件,并且显然
base64
编码的数据无法正确压缩。

使用我的个人资料图片的示例输出:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body cz-shortcut-listen="true">
    <pre>
data:image/png;base64,bx89PNGrnx1anx00x00x00rIHDRx00x00x01x00x00x00x01x00x08x03x00x00x00kxacXTx00x00x03x00PLTEx19x19x1dxffxffxffxd4xd5xe1xd3xd4xe1xd2xd3xe0x1fx11x11x15x10x10x13x18x18x1cx13x14x18x15x16x1ax16x17x1bxd5xd6xe2x15x15x19xfexfexffxdcxddxe9x13x12x16xdexdfxebxddxdexebxfdxfcxfdxd7xd8xe4xfdxfdxfex0fx0fx12xdaxdbxe7x0ex0ex12xd2xd3xdfxf9xf9xfbx1d9xf3xf3xf7x1ax1ax1exdfxe0xe9xfaxfaxfcxf1xf0xf3xdcxdcxe8xd7xd7xe3xf6xf6xf9xe0xe1xebxfcxfbxfdx174x1a7xebxecxf1xe4xe5xedxf7xf7xf9xe6xe7xeexd9xdaxe6xeexefxf4xa4xa2xadxc7xc8xd3xe8xe9xefx9bx98xa7x1ex1dxd0xd1xddxf5xf5xf8xc1xc2xcdxb8xb6xbfxb3xb1xbcxe2xe3xecxf8xf8xfbx9fx9dxa877xeexedxefllrdcixf4xf4xf8xd8xd9xe6x92x92x9cvvzxf1xf1xf5xb9xb9xc4xecxedxf3xa5xa6xaeTTX//3x8ax85x97CCFxe1xe0xe3xd8xd9xe4xdexddxe2xc3xc1xc7xc5xc4xce+a559x8bx8bx92x91x8cx9dxeaxeaxefxccxccxd8xf5xf4xf5xbcxbcxc8x86x83x92x97x94xa3xc7xc5xca9/Lxe4xe3xe5xabxa9xb2xb1xadxb6x85x80x91rrvxbfxbfxca225xcdxcbxd0x9cx95xa2xc0xbbxc3xeaxe9xebxa8xa5xb1xcexcdxcfx9dx9ax9bNOSxdexdexe8x88x82x7fxd5xd3xd9x8dx88x99xe7xe6xe9xb7xb6xb6xa1xa0xa2GZx92x8fx8ex98x95x96hhkdx8fx8fx97x88x88x8bxcaxc9xccxb4xb4xbcxadx7fx83xd1x98x93xc2x90x93IY0ATvx82x90vpx83x7fyx8cxafxadxbdxaaxa8xa9x84x7fx80x83xf0zBEx82JKPxd4xd1xd3zyxabxacxb7xe3xe3xebxaexadxaexeexacxa4xe8xa6x9fZRgxbdx8ax8axa0x93GFJxb8x86x87xfcxebxe8vx88xd9x9fx97ODe7WKl4Fxd8xd6xdbxfdx80Dxf9xbaxbaxbcxa5xa2xa2xf9xe4xe2xe9xeaxf3xf6xbbxb3xffxf6xf4x95iqxefxc3xbexe1xa8x9fA6VH/x1ex141xcfxcfxd8A8Qx93xx8dxe5xb4xc9xffxd9xe9x84lx83xdbxdaxddxd8xd8xd8xaezxa2vxcax93x91xaawxb3x82x84WWx97mtxaaxa7xb6YmernAxdbrjbvx90x81x90xffxc3xa7xa9x86x9cxfbxd6xd1xf6xd3xcfxf4xcaxc5x18x19x1dxfcxf1xf0xd6xa6xa3x9fsyxa0x80ngz4NROPxa3Y8xf5x83Oxc1h+x89N3xaex80jxfbxa9x83x91x89x97xf8x97ixd4xb3xc6xbax9bxafxf1xc3xd7xfaxcdxdfx8dsx89xe9xb6xb1xddxc4xc5x87hxffxeexecxcexbfxc3xe8xdfxe1xf7xc9xc2xb8xa4xabkx81vG1xe3x93m7Hxe0x86Zwvxfexdaxc9xe4xc9xbexfdx9fsxffxe9xdbxffxe1xd1xcaxa6xbaxd5xd6xd9xcbx9dxb3xecxb9xcexa7xa3xa0xdfxdbxd4xe3x00x00rxIDATxx9cxedx9dux1bxd9x16xc7xb93Cx1ex02x01x12x10x08txeeZx9cxb6Hxb4PJxa9Axa1xb4xddnuwxddxbaxf7uxebxdfxb7xebxbaxcbwxeexfbxe4x13DfRxb6xa4x8fx19xf6xffxe1xb3wfxfbxb9xbfx93sxcc=</pre
    >
    <img
      src="data:image/png;base64,bx89PNGrnx1anx00x00x00rIHDRx00x00x01x00x00x00x01x00x08x03x00x00x00kxacXTx00x00x03x00PLTEx19x19x1dxffxffxffxd4xd5xe1xd3xd4xe1xd2xd3xe0x1fx11x11x15x10x10x13x18x18x1cx13x14x18x15x16x1ax16x17x1bxd5xd6xe2x15x15x19xfexfexffxdcxddxe9x13x12x16xdexdfxebxddxdexebxfdxfcxfdxd7xd8xe4xfdxfdxfex0fx0fx12xdaxdbxe7x0ex0ex12xd2xd3xdfxf9xf9xfbx1d9xf3xf3xf7x1ax1ax1exdfxe0xe9xfaxfaxfcxf1xf0xf3xdcxdcxe8xd7xd7xe3xf6xf6xf9xe0xe1xebxfcxfbxfdx174x1a7xebxecxf1xe4xe5xedxf7xf7xf9xe6xe7xeexd9xdaxe6xeexefxf4xa4xa2xadxc7xc8xd3xe8xe9xefx9bx98xa7x1ex1dxd0xd1xddxf5xf5xf8xc1xc2xcdxb8xb6xbfxb3xb1xbcxe2xe3xecxf8xf8xfbx9fx9dxa877xeexedxefllrdcixf4xf4xf8xd8xd9xe6x92x92x9cvvzxf1xf1xf5xb9xb9xc4xecxedxf3xa5xa6xaeTTX//3x8ax85x97CCFxe1xe0xe3xd8xd9xe4xdexddxe2xc3xc1xc7xc5xc4xce+a559x8bx8bx92x91x8cx9dxeaxeaxefxccxccxd8xf5xf4xf5xbcxbcxc8x86x83x92x97x94xa3xc7xc5xca9/Lxe4xe3xe5xabxa9xb2xb1xadxb6x85x80x91rrvxbfxbfxca225xcdxcbxd0x9cx95xa2xc0xbbxc3xeaxe9xebxa8xa5xb1xcexcdxcfx9dx9ax9bNOSxdexdexe8x88x82x7fxd5xd3xd9x8dx88x99xe7xe6xe9xb7xb6xb6xa1xa0xa2GZx92x8fx8ex98x95x96hhkdx8fx8fx97x88x88x8bxcaxc9xccxb4xb4xbcxadx7fx83xd1x98x93xc2x90x93IY0ATvx82x90vpx83x7fyx8cxafxadxbdxaaxa8xa9x84x7fx80x83xf0zBEx82JKPxd4xd1xd3zyxabxacxb7xe3xe3xebxaexadxaexeexacxa4xe8xa6x9fZRgxbdx8ax8axa0x93GFJxb8x86x87xfcxebxe8vx88xd9x9fx97ODe7WKl4Fxd8xd6xdbxfdx80Dxf9xbaxbaxbcxa5xa2xa2xf9xe4xe2xe9xeaxf3xf6xbbxb3xffxf6xf4x95iqxefxc3xbexe1xa8x9fA6VH/x1ex141xcfxcfxd8A8Qx93xx8dxe5xb4xc9xffxd9xe9x84lx83xdbxdaxddxd8xd8xd8xaezxa2vxcax93x91xaawxb3x82x84WWx97mtxaaxa7xb6YmernAxdbrjbvx90x81x90xffxc3xa7xa9x86x9cxfbxd6xd1xf6xd3xcfxf4xcaxc5x18x19x1dxfcxf1xf0xd6xa6xa3x9fsyxa0x80ngz4NROPxa3Y8xf5x83Oxc1h+x89N3xaex80jxfbxa9x83x91x89x97xf8x97ixd4xb3xc6xbax9bxafxf1xc3xd7xfaxcdxdfx8dsx89xe9xb6xb1xddxc4xc5x87hxffxeexecxcexbfxc3xe8xdfxe1xf7xc9xc2xb8xa4xabkx81vG1xe3x93m7Hxe0x86Zwvxfexdaxc9xe4xc9xbexfdx9fsxffxe9xdbxffxe1xd1xcaxa6xbaxd5xd6xd9xcbx9dxb3xecxb9xcexa7xa3xa0xdfxdbxd4xe3x00x00rxIDATxx9cxedx9dux1bxd9x16xc7xb93Cx1ex02x01x12x10x08txeeZx9cxb6Hxb4PJxa9Axa1xb4xddnuwxddxbaxf7uxebxdfxb7xebxbaxcbwxeexfbxe4x13DfRxb6xa4x8fx19xf6xffxe1xb3wfxfbxb9xbfx93sxcc="
      alt=""
    />
  </body>
</html>

django postgresql blob
1个回答
0
投票

修复模型和视图:

  1. 确保 BinaryField 正确处理原始二进制数据:确认 模型中的 BinaryField 直接存储原始二进制数据, 不是任何被操纵或预编码的数据。
  2. 更新您的视图以正确处理 Base64 编码:确保 从数据库检索的二进制数据已正确编码 作为有效的 Base64 字符串。

导入base64

from django.shortcuts import render

from .models import ImageFile
def image_view(request, id):

document_file = ImageFile.objects.filter(id=id).first()
data = ""
if document_file and document_file.file:  # Ensure `file` is not None
    data = base64.b64encode(document_file.file).decode('utf-8')
return render(request, "image.html", {"data": data})

修复 HTML 模板

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Image Viewer</title>
  </head>
  <body>
    {% if data %}
      <img src="data:image/png;base64,{{ data }}" alt="Image" />
    {% else %}
      <p>No image data available.</p>
    {% endif %}
  </body>
</html>
  1. 二进制字段存储:

    models.BinaryField 存储原始二进制数据,因此当您调用 upload.read() 在你的小部件中,确保数据没有被修改 (例如,通过部分读取或编码)。

  2. Base64 编码:

    Base64 编码必须在渲染图像时进行 在浏览器中,而不是在将数据存储到数据库之前。文件

  3. 验证:

    确保上传的文件确实是有效的PNG图像。你可以 使用 Pillow 等 Python 库来验证文件类型 上传。

  4. 压缩:

    首选存储原始二进制数据(而不是预编码的 Base64) 为了效率。 Base64 编码增加存储大小 大约 33%,所以最好只在 检索阶段。

© www.soinside.com 2019 - 2024. All rights reserved.