首页 > 解决方案 > 在 FE 上下载/引用期间是否可以交换 FileField 的文件名?

问题描述

我正在使用 Django+DRF 来允许上传/保留/服务用户上传的资产文件。我需要让用户稍后下载上传的资产。在文件上传时,我需要对其真实名称进行 md5 哈希处理,并将其保存到文件系统中,并以该哈希作为文件名。然后,当用户想在 FE 上下载/查看它时,假设他上传了一个文件 'cute_cat.jpg',我希望他得到名为 'cute_cat.jpg' 的文件而不是 3c808e77fc1b0aee4435533690be458d (名称是一个问题,另一个一种是浏览器将不带扩展名的文件作为应用程序/八位字节流提供,我希望它将“.jpg”(最初)文件呈现为图像)

我觉得我需要用 'Content-Disposition: attachment; 注入一个 HTTP 标头;filename=cute_cat.jpg'(我将真实文件名存储在 DB 中)在通往 DRF 的 Response() 途中的某个地方,但我不确定在什么时候我要这样做,即使它是可能的......我尝试了很多东西,主要是为序列化程序实现自定义字段并在那里注入一个自定义 URL,但显然这不是办法,因为没有地方可以将标头注入到文本 URL 并且尝试输出没有意义API 视图中带有标头的请求对象...

这是我的模型:

def get_full_path(instance, filename):
  return '/'.join([
    instance.user.name,
    hashlib.md5(filename.encode()).hexdigest()
  ])

class CustomAsset(models.Model):
  file = models.FileField(blank=False, null=False, upload_to=get_full_path)
  real_file_name = models.CharField(max_length=255, blank=False, null=False)
  user = models.ForeignKey(...)

序列化程序/API 视图中没有任何内容被覆盖。

提前非常感谢。

标签: djangodjango-rest-framework

解决方案


首先您需要了解API,您可以返回的只是URL。

现在,处理文件格式和内容类型管理是浏览器的职责。您需要在这里做的是通过您的应用程序控制器管理文件。当您返回网址时,您会返回类似的网址。

http://example.com/file/<md5> 

访问时,此 url 通过控制器为文件提供服务,并带有修改的内容处置标头,并将文件作为响应返回。

一个简单的例子看起来像。

在您的 urls.py 中,添加一条新路线。

url(r'^file/(?P<identifier>[\w\d\-_]+)$', custom_file_server, name="custom_file_server"),

然后根据您的需要提供文件。一个简单的例子就是这样。

def custom_file_server(request, identifier):
    ## Get the file name from db by querying from identifier
    file_name = "abc.jpg"
    absolute_file_path = os.path.join(settings.BASE_DIR, "media/"+identifier)
    response = FileResponse(open(absolute_file_path, 'rb'))
    response['Content-Disposition'] = "attachment; filename={}".format(file_name)
    response['Content-Type'] = 'image/jpeg'
    return response

上面的代码未经测试,但概念仍然如此。如果您有任何问题,请告诉我。


推荐阅读