使用 Python/Boto/Django 实现 S3 直接上传

要使用 Python 和 Boto3(AWS SDK for Python)直接从 Django 上传文件到 S3,你需要配置 AWS 的 S3 存储桶,并在 Django 项目中设置 boto3 来与 S3 进行交互。

问题背景

在使用 Plupload 和 AWS S3 直接上传时,试图使用 Python/Boto/Django 进行构建策略并上传文件,但一直收到错误消息或连接重置,无法成功上传。

解决方案

解决方案 1:使用纯 Python

步骤 1:设置策略文档和签名

###### EDIT ONLY THE FOLLOWING ITEMS ######

DEBUG = 1
AWS_SECRET_KEY = "MySecretKey"
AWS_ACCESS_KEY = "MyAccessKey"
HTML_NAME = "S3PostForm.html"
EXPIRE_DATE = "2015-01-01T00:00:00Z" # Jan 1, 2015 gmt
FILE_TO_UPLOAD = "${filename}"
BUCKET = "media.mysite.com"
KEY = ""
ACL = "public-read" # or "private"
SUCCESS = "http://media.mysite.com/success.html"
CONTENT_TYPE = ""
CONTENT_LENGTH = 1024**3 # One gigabyte
HTTP_OR_HTTPS = "http" # Or "https" for better security
PAGE_TITLE = "My Html Upload to S3 Form"
ACTION = "%s://%s.s3.amazonaws.com/" % (HTTP_OR_HTTPS, BUCKET)

###### DON'T EDIT FROM HERE ON DOWN ######

policy_document_data = {
"expire": EXPIRE_DATE,
"bucket_name": BUCKET,
"key_name": KEY,
"acl_name": ACL,
"success_redirect": SUCCESS,
"content_name": CONTENT_TYPE,
"content_length": CONTENT_LENGTH,
}

policy_document = """
{"expiration": "%(expire)s",
  "conditions": [ 
    {"bucket": "%(bucket_name)s"}, 
    ["starts-with", "$key", "%(key_name)s"],
    {"acl": "%(acl_name)s"},
    {"success_action_redirect": "%(success_redirect)s"},
    ["starts-with", "$Content-Type", "%(content_name)s"],
    ["content-length-range", 0, %(content_length)d]
  ]
}
""" % policy_document_data

policy = base64.b64encode(policy_document)
signature = base64.b64encode(hmac.new(AWS_SECRET_KEY, policy, hashlib.sha1).digest())

html_page_data = {
"page_title": PAGE_TITLE,
"action_name": ACTION,
"filename": FILE_TO_UPLOAD,
"access_name": AWS_ACCESS_KEY,
"acl_name": ACL,
"redirect_name": SUCCESS,
"policy_name": policy,
"sig_name": signature,
"content_name": CONTENT_TYPE,
}

html_page = """
<html> 
 <head>
  <title>%(page_title)s</title> 
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 </head>
<body>
 <form action="%(action_name)s" method="post" enctype="multipart/form-data">
  <input type="hidden" name="key" value="%(filename)s">
  <input type="hidden" name="AWSAccessKeyId" value="%(access_name)s">
  <input type="hidden" name="acl" value="%(acl_name)s">
  <input type="hidden" name="success_action_redirect" value="%(redirect_name)s">
  <input type="hidden" name="policy" value="%(policy_name)s">
  <input type="hidden" name="signature" value="%(sig_name)s">
  <input type="hidden" name="Content-Type" value="%(content_name)s">

  <!-- Include any additional input fields here -->

  Browse to locate the file to upload:<br \> <br \>

  <input name="file" type="file"><br> <br \>
  <input type="submit" value="Upload File to S3"> 
 </form> 
</body>
</html>
""" % html_page_data

with open(HTML_NAME, "wb") as f:
    f.write(html_page)

###### Dump output if testing ######
if DEBUG:

    if 1: # Set true if not using the LEO editor
        class G:
            def es(self, data):print(data)
        g = G()

    items = [
    "",
    "",
    "policy_document: %s" % policy_document,
    "ploicy: %s" % policy,
    "signature: %s" % signature,
    "",
    "",
    ]
    for item in items:
        g.es(item)

步骤 2:创建 HTML 上传表单

使用 html_page_data 字典中的值动态创建 HTML 上传表单。

步骤 3:保存上传表单

将 html_page 变量的内容保存到 HTML 文件中。

解决方案 2:使用 boto

步骤 1:导入 boto 库

from boto.s3 import connection

步骤 2:设置 S3 连接

conn = connection.S3Connection(AWS_ACCESS_KEY,AWS_SECRET_KEY)

步骤 3:构建表单参数

使用 conn.build_post_form_args 方法构建表单参数。

步骤 4:创建 HTML 上传表单

使用 form_fields 变量中的值动态创建 HTML 上传表单。

步骤 5:保存上传表单

将 html_page 变量的内容保存到 HTML 文件中。

步骤 6:创建成功页面

创建一个 HTML 页面来显示上传成功的消息。

步骤 7:保存成功页面

将 success_page 变量的内容保存到 HTML 文件中。

代码例子

解决方案 1:使用纯 Python

python 复制代码
# Import required libraries
import base64
import hmac, hashlib

# Set up policy document data
policy_document_data = {
    "expire": EXPIRE_DATE,
    "bucket_name": BUCKET,
    "key_name": KEY,
    "acl_name": ACL,
    "success_redirect": SUCCESS,
    "content_name": CONTENT_TYPE,
    "content_length": CONTENT_LENGTH,
}

# Construct the policy document
policy_document = """
    {"expiration": "%(expire)s",
      "conditions": [
        {"bucket": "%(bucket_name)s"},
        ["starts-with", "$key", "%(key_name)s"],
        {"acl": "%(acl_name)s"},
        {"success_action_redirect": "%(success_redirect)s"},
        ["starts-with", "$Content-Type", "%(content_name)s"],
        ["content-length-range", 0, %(content_length)d]
      ]
    }
    """ % policy_document_data

# Encode the policy document using base64
policy = base64.b64encode(policy_document)

# Construct the signature using HMAC-SHA1
signature = base64.b64encode(hmac.new(AWS_SECRET_KEY, policy, hashlib.sha1).digest())

# Set up HTML page data
html_page_data = {
    "page_title": PAGE_TITLE,
    "action_name": ACTION,
    "filename": FILE_TO_UPLOAD,
    "access_name": AWS_ACCESS_KEY,
    "acl_name": ACL,
    "redirect_name": SUCCESS,
    "policy_name": policy,
    "sig_name": signature,
    "content_name": CONTENT_TYPE,
}

# Construct the HTML page
html_page = """
    <html>
        <head>
            <title>%(page_title)s</title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        </head>
        <body>
            <form action="%(action_name)s" method="post" enctype="multipart/form-data">
                <input type="hidden" name="key" value="%(filename)s">
                <input type="hidden" name="AWSAccessKeyId" value="%(access_name)s">
                <input type="hidden" name="acl" value="%(acl_name)s">
                <input type="hidden" name="success_action_redirect" value="%(redirect_name)s">
                <input type="hidden" name="policy" value="%(policy_name)s">
                <input type="hidden" name="signature" value="%(sig

如果你希望直接从前端通过 JavaScript 将文件上传到 S3,可以进一步实现签名请求(presigned URL),但上述方法主要通过 Django 后端来处理文件上传。

相关推荐
码界筑梦坊5 分钟前
基于Flask的当当网畅销图书榜单可视化分析系统的设计与实现
后端·python·flask·毕业设计
m0_748232929 分钟前
纯 Python、Django、FastAPI、Flask、Pyramid、Jupyter、dbt 解析和差异分析
python·django·fastapi
wjs202413 分钟前
jQuery UI 下载指南
开发语言
程序员小续17 分钟前
现代前端工程化实践:高效构建的秘密
开发语言·前端·javascript·vue.js·webpack·前端框架·ecmascript
No8g攻城狮19 分钟前
【异常解决】在idea中提示 hutool 提示 HttpResponse used withoud try-with-resources statement
java·开发语言·ide·intellij-idea
赵瑽瑾37 分钟前
Lua语言的嵌入式系统
开发语言·后端·golang
霍璟琅38 分钟前
Delphi语言的数据可视化
开发语言·后端·golang
funsion40 分钟前
Lua中文语言编程源码-第十一节,其它小改动汉化过程
c语言·开发语言·中文分词·lua
NPE~1 小时前
[渗透测试]热门搜索引擎推荐— — fofa篇
开发语言·搜索引擎·渗透测试·php·教程·软件推荐·fofa
霍熠烁1 小时前
Objective-C语言的云计算
开发语言·后端·golang