DjangoAdmin 将 BinaryField 渲染为图像

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

我编写了中间件来捕获请求并在管理页面上查看它们。它成功查看原始文本请求正文,但在图像渲染上失败。
admin.py

class RequestLogEntryAdmin(admin.ModelAdmin):
    fieldsets = (
        ('Request', {
            'fields': ('request_headers', 'request_size', 'request_body_'),
        })
    )
    
    def request_body_(self, obj):
        if b'Content-Type: image/png' in base64.b64decode(obj.request_body):
            return obj.image_handler(bytes(obj.request_body))
        return bytes(obj.request_body)

模型.py

class RequestLogEntry(models.Model):
    # ...
    request_body = models.BinaryField(null=True)
    # ...
    
    def image_handler(self, binaryfield):
        return mark_safe(f'<img src="data:image/png;base64,{binaryfield}" width="150" height="150" />')

保存 request.body 之前正在进行 base64 编码
中间件.py

    # ...
    log_entry.request_body = base64.b64encode(request.body)
    # ...

当前代码产生以下结果:Broken image

Base64 解码后的 request.body 如下所示:Raw request body 我的猜测是一些额外的数据与图像字节混合在一起(例如“Content-Disposition”和“Content-Type”标头),但我不确定如何从请求正文中将其删除。

python django binary base64 django-admin
1个回答
0
投票

当您像这样编码

HttpRequest.body
时:

base64.b64encode(request.body)

您实际上是将原始 HTTP 请求正文(这是一个

bytestring
)编码为 Base64 [wikipedia.org] 编码字符串。

HTTP 是基于文本的协议。正文和标题表示为字符序列。 Django 通过将原始主体保留在

HttpRequest.body
中来保留 HTTP 的这一功能,供任何想要在这个低级别工作的人使用。

但是由于请求包含文件,你应该这样处理:

if request.FILES:
    file = request.FILES.get("image")
    if file:
        log_entry.request_body = file.read() #[1]

现在

image_handler()
必须稍微改变一下,因为
binaryfield
是二进制数据的原始位,而不是 Base64 字符串。

def image_handler(self, binaryfield):
    return mark_safe(f"<img src='data:image/png;base64,{base64.b64encode(binaryfield)}' width='150' height='150' />")

[1]

read()
上调用
UploadedFile
时,您实际上是将
UploadedFile
中的全部数据读取到内存中。使用此方法时要小心:如果上传的文件很大,它可能会压垮您的系统。

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