Django:在不创建模型的情况下允许下载S3上的各种媒体文件(并隐藏S3存储)

1 投票
2 回答
956 浏览
提问于 2025-04-18 02:00

我在S3上有成千上万的媒体文件。

  • 这些文件的类型可能是纯文本、HTML、XML、PDF、二进制文件、压缩包等。
  • 另外,有些文件可能是经过gzip压缩的。

我想在Django应用中展示这些文件。我不想让用户直接访问S3。在某些情况下,我还想在展示之前对文件进行一些修改。
比如:

  • /base/path/file_name_aaa.txt.gz <--- 从S3下载,解压后通过Django展示格式化的文本
  • /base/path/file_name_aaa.pdf <--- 从S3下载并通过Django展示为PDF
  • /base/path/file_name_bbb.pdf.gz <--- 从S3下载,解压后通过Django展示为PDF
  • /base/path/file_name_ccc.xml.gz <--- 从S3下载,解压,替换一些内容,然后通过Django展示为解压后的XML

我已经完成了纯文本的部分:

from boto.s3.connection import S3Connection
import zlib

def get_gzipped_content(stream):
    content = ''
    for part in stream_decompress(stream):
        content += part
    return content

def stream_decompress(stream):
    '''
    decompress s3 gzipped stream
    http://stackoverflow.com/questions/12571913/python-unzipping-stream-of-bytes
    '''
    dec = zlib.decompressobj(16+zlib.MAX_WBITS)  # same as gzip module
    for chunk in stream:
        rv = dec.decompress(chunk)
        if rv:
            yield rv
conn = S3Connection(aws_key, aws_secret)
fname = 'aaa/bbb/ccc_1234.txt.gz'
key = conn.get_bucket('my_bucket').get_key(fname)
if fname.lower().endswith('.gz'):
    content = get_gzipped_content(key)
else:
    content = key.get_contents_as_string()
(render content as string in django)

我希望能得到关于其他文件类型和gzip的帮助。

2 个回答

2

除了kubus提到的内容,我还在想怎么让浏览器“显示”文件,而不是“下载”它。

response = HttpResponse(ContentFile(content), content_type=mimetypes.guess_type(attach_id)[0])
if <this file should be forced download, and not render in browser>:
    response['Content-Disposition'] = "attachment; filename=%s" % filename 
# else, it will try to render in browser.
1

你可以使用一个标准的mimetype模块来根据文件名判断内容类型和编码,比如:

In [1]: import mimetypes

In [2]: mimetypes.guess_type('hello.txt.gz')
Out[2]: ('text/plain', 'gzip')

In [3]: mimetypes.guess_type('hello.pdf.gz')
Out[3]: ('application/pdf', 'gzip')

In [4]: mimetypes.guess_type('hello.pdf')
Out[4]: ('application/pdf', None)

https://docs.python.org/2/library/mimetypes.html

撰写回答