使用 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 分钟前
【C++】 —— 笔试刷题day_5
开发语言·c++
观无16 分钟前
C#的简单工厂模式、工厂方法模式、抽象工厂模式
java·开发语言·c#
前端开发张小七18 分钟前
Python 学习总结-2
python
蜡笔小新..24 分钟前
开发、科研、日常办公工具汇总(自用,持续更新)
论文阅读·人工智能·python·插件·zotero
发财哥fdy31 分钟前
3.12-3 html
人工智能·python·tensorflow
斯密码赛我是美女41 分钟前
日志Python安全之SSTI——Flask/Jinja2
后端·python·flask
图图不是秃秃1 小时前
Java构造方法详解:从入门到实战
java·开发语言
明月看潮生1 小时前
青少年编程与数学 02-010 C++程序设计基础 44课题、QT
开发语言·c++·qt·青少年编程·编程与数学
YuiGod1 小时前
《从零开始DeepSeek R1搭建本地知识库问答系统》六:关于聊天模型 API Key 的使用与调用 Embedding 模型
python·langchain·deepseek
柳如烟@1 小时前
docker python:latest镜像 允许ssh远程
python·docker·ssh