Django Admin中BinaryField渲染图片失败问题求助
问题解决:Django Admin渲染捕获的图片请求体失败
问题根源
你当前的代码直接存储了完整的multipart/form-format请求体(包含表单边界、Content-Disposition、Content-Type等元数据),而非纯图片字节。当你把这些混杂数据当成图片base64渲染时,浏览器无法识别,自然显示损坏的图片。
解决方案
1. 中间件中提取纯图片字节
修改middleware.py,解析multipart请求,提取出图片的原始字节再编码存储:
import base64 from django.http.multipartparser import MultiPartParser # 中间件的__call__方法内 def __call__(self, request): response = self.get_response(request) request_body = b"" if request.method in ["POST", "PUT", "PATCH"]: # 判断是否为文件上传请求 if request.content_type and request.content_type.startswith("multipart/form-data"): try: # 解析multipart表单数据 parser = MultiPartParser(request.META, request, request.upload_handlers) data, files = parser.parse() # 提取第一个上传的文件字节(根据业务调整,支持多文件可遍历files) for file in files.values(): file.seek(0) request_body = file.read() break except Exception: # 解析失败时回退到原始请求体 request_body = request.body else: # 非文件上传请求直接存原始内容 request_body = request.body # 编码后保存日志 log_entry = RequestLogEntry.objects.create( # 填充其他字段... request_body=base64.b64encode(request_body) if request_body else None ) return response
2. 模型层调整图片渲染逻辑
修改models.py,确保用纯图片字节生成合法的data URI:
from django.utils.safestring import mark_safe import base64 class RequestLogEntry(models.Model): request_body = models.BinaryField(null=True) # ...其他字段 def get_image_html(self, img_type="png"): image_bytes = base64.b64decode(self.request_body) image_base64 = base64.b64encode(image_bytes).decode("utf-8") return mark_safe(f'<img src="data:image/{img_type};base64,{image_base64}" width="150" height="150" />')
3. Admin层优化内容展示逻辑
修改admin.py,通过文件头判断是否为图片,分别渲染:
import base64 class RequestLogEntryAdmin(admin.ModelAdmin): fieldsets = ( ('Request', { 'fields': ('request_headers', 'request_size', 'request_body_'), }) ) def request_body_(self, obj): if not obj.request_body: return "-" decoded_body = base64.b64decode(obj.request_body) # 通过文件头判断图片类型 if decoded_body.startswith(b'\x89PNG\r\n\x1a\n'): return obj.get_image_html("png") elif decoded_body.startswith(b'\xff\xd8\xff'): return obj.get_image_html("jpeg") elif decoded_body.startswith(b'GIF87a') or decoded_body.startswith(b'GIF89a'): return obj.get_image_html("gif") else: # 文本内容解码展示,处理编码异常 return decoded_body.decode("utf-8", errors="replace")
关键说明
- multipart请求体包含大量非图片的元数据,必须解析后提取纯文件内容才能正常渲染。
- 通过文件头判断图片类型比依赖请求头更可靠,避免请求头被篡改或不准确的情况。
- 增加异常处理,防止解析失败导致日志记录或页面展示崩溃。
内容的提问来源于stack exchange,提问作者Yaourt
相关产品推荐
相关产品推荐

