Django-s3direct上传图片

时间:2014-04-09 08:03:55

标签: python django amazon-s3 django-forms django-admin

我想使用django-s3direct,我想在管理面板中上传许多图片。

1)所有当我尝试上传图片/文件时出现错误“哎呀,文件上传失败,请再试一次”?     当我刷新页面。名称文件在输入中。但是我的输入“保存”被禁用:/

修改    我从设置中删除了:

AWS_SECRET_ACCESS_KEY = ''
AWS_ACCESS_KEY_ID = ''
AWS_STORAGE_BUCKET_NAME = ''

现在我没有收到错误但是文件没有上传:/所有时间黑色进度条..

2)如何上传多个图片?没有内联..请帮助我并给出一些建议?我是新手......

我有Django 1.5.5。现在我使用内联,我不知道下一步是什么。

1 个答案:

答案 0 :(得分:2)

您需要编辑目标S3存储桶的某些权限属性,以便最终请求具有足够的权限来写入存储桶。登录AWS控制台并选择S3部分。选择适当的存储桶,然后单击“属性”选项卡。选择“权限”部分,并提供三个选项(添加更多权限,编辑存储桶策略和编辑CORS配置)。 CORS(跨源资源共享)将允许您的应用程序访问S3存储桶中的内容。每个规则都应指定一组域,从这些域授予对存储桶的访问权限,以及从这些域允许的方法和标头。

要在您的应用程序中使用此功能,请单击“添加CORS配置”并输入以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
   <CORSRule>
        <AllowedOrigin>yourdomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

在CORS窗口中单击“保存”,然后在存储桶的“属性”选项卡中再次“保存”。 这告诉S3允许任何域访问存储桶,并且该请求可以包含任何标头。为安全起见,您可以将“AllowedOrigin”更改为仅接受来自您域的请求。 如果您希望专门为此应用程序使用S3凭据,则可以在AWS账户页面中生成更多密钥。这提供了进一步的安全性,因为您可以指定这组密钥能够执行的非常具体的请求集。如果这对您更有利,那么您还需要在S3存储桶的“编辑存储桶策略”选项中设置IAM用户。 AWS的网页上有各种指南,详细说明了如何实现这一目标。

设置客户端代码 此设置不需要任何其他非标准Python库,但是在客户端完成实现需要一些脚本。 本文介绍s3upload.js脚本的用法。从项目的repo(使用Git或其他)获取此脚本,并将其存储在应用程序的静态目录中。该脚本目前依赖于JQuery和Lo-Dash库。在您的应用程序中包含这些内容将在本指南的后面部分介绍。 现在可以创建HTML和JavaScript来处理文件选择,从Python应用程序获取请求和签名,然后最终发出上载请求。 首先,在应用程序的模板目录中创建一个名为account.html的文件,并为您的应用程序适当填充头部和其他必要的HTML标记。在此HTML文件的正文中,包含一个文件输入和一个包含上载进度状态更新的元素。

<input type="file" id="file" onchange="s3_upload();"/>
<p id="status">Please select a file</p>
<div id="preview"><img src="/static/default.png"  /></div>

<form method="POST" action="/submit_form/">
    <input type="hidden" id="" name="" value="/static/default.png" />
    <input type="text" name="example" placeholder="" /><br />
    <input type="text" name="example2" placeholder="" /><br /><br />
    <input type="submit" value="" />
</form>

预览元素最初包含默认图像。当用户选择新图像时,这两个都由JavaScript更新,如下所述。 因此,当用户最终单击提交按钮时,图像的URL以及用户的其他详细信息将提交到所需的端点以进行服务器端处理。当用户选择文件时,将调用JavaScript方法s3_upload()。该方法的创建和人口如下。 接下来,在HTML文件account.html中包含三个依赖脚本。如果将此文件放在/ static以外的目录中,则可能需要调整files3upload.js的src属性:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript" src="https://raw.github.com/bestiejs/lodash/v1.1.1/dist/lodash.min.js"></script>
<script type="text/javascript" src="/static/s3upload.js"></script>

脚本的顺序很重要,因为需要在此序列中满足依赖性。如果您希望托管自己的JQuery和Lo-Dash版本,请相应地调整thesrc属性。 最后,在一个块中,再次在同一文件中声明一个JavaScript函数s3_upload()来处理文件上载。该块需要存在于包含三个依赖项之下:

function s3_upload(){
    var s3upload = new S3Upload({
        file_dom_selector: 'file',
        s3_sign_put_url: '/sign_s3_upload/',

        onProgress: function(percent, message) {
            $('#status').html('Upload progress: ' + percent + '%' + message);
        },
        onFinishS3Put: function(url) {
            $('#status').html('Upload completed. Uploaded to: '+ url);
            $("#image_url").val(url);
            $("#preview").html('<img src="'+url+'" style="width:300px;" />');
        },
        onError: function(status) {
            $('#status').html('Upload error: ' + status);
        }
    });
}

此函数创建一个新的S3Upload实例,向其传递文件输入元素,从中检索签名请求的URL和三个函数。 最初,该函数向由s3_sign_put_url参数表示的URL发出请求,将文件名和mime类型作为GET参数传递。服务器端代码(在下一节中介绍)解释请求并响应预览要上载到S3的文件的URL和签名请求,然后该函数将该文件异步上传到您的存储桶。 该函数将上传更新发布到onProgress()函数,如果上传成功,则调用onFinishS3Put()并将Python应用程序视图返回的URL作为参数接收。如果由于任何原因上传失败,将调用onError()并且thestatus参数将描述错误。 如果在实现系统后发现页面无法正常工作,请考虑使用console.log()记录onError()回调中发生的任何错误,并使用浏览器的错误控制台来帮助诊断问题。 如果成功,现在将使用用户选择的图像更新预览div,隐藏的输入字段将包含图像的URL。现在,一旦用户完成了表单的其余部分并单击了提交,所有信息都可以发布到同一个端点。 优良作法是告知用户任何形式的应用程序(基于Web或基于设备)的任何长时间活动,并显示更改的更新。因此,可以使用状态方法,例如,显示加载GIF以指示上载正在进行,然后可以在上载完成时隐藏。如果没有此类信息,用户可能会怀疑页面已崩溃,并可能尝试刷新页面或以其他方式中断上传过程。

设置服务器端Python代码

生成临时签名,使用该签名可以签署上载请求。此临时签名使用帐户详细信息(AWS访问密钥和秘密访问密钥)作为签名的基础,但用户将无法直接访问此信息。签名过期后,具有相同签名的上载请求将不会成功。 如前所述,本文将介绍Flask框架的应用程序的生成,尽管其他Python框架的步骤将类似。使用Python 3的读者在继续之前应该考虑Flask网站上的相关信息。 首先创建主应用程序文件application.py,然后适当地设置骨架应用程序:

from flask import Flask, render_template, request
from hashlib import sha1
import time, os, json, base64, hmac, urllib

app = Flask(__name__)

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)

稍后将需要当前未使用的import语句。 使用Python 3的读者应该导入urllib.parse来代替urllib。 接下来,在同一文件中,您需要创建视图,负责在向各种URL发出请求时将正确的信息返回给用户的浏览器。首先定义对/ account返回页面account.html的请求的视图,其中包含用户要完成的表单:

@app.route("/account/")
def account():
    return render_template('account.html')

请注意,应用程序的视图需要放在app = Flask(__name__) and if __name__ == '__main__':的{​​{1}}行之间。 现在在同一个Python文件中创建视图,该视图负责生成和返回客户端JavaScript可以上传图像的签名。这是客户端在尝试上传到S3之前发出的第一个请求。该视图响应对/ sign_s3 /:

的请求
application.py

使用Python 3的读者应该使用urllib.parse.quote_plus()来引用签名。 此代码执行以下步骤: •请求收到/ sign_s3 /,AWS密钥和S3存储桶名称从环境加载。

•要上载的对象的名称和mime类型是从请求的GET参数中提取的(此阶段可能在其他框架中有所不同)。

•签名的到期时间已设定,并构成签名临时性质的基础。如图所示,这最好用作相对于当前UNIX时间的函数。在此示例中,签名将在Python执行该行代码后10秒到期。

•标题行告诉S3授予哪些访问权限。在这种情况下,该对象将公开下载。 •现在可以根据对象信息,标题和到期时间构建PUT请求。

•签名生成为已编译的AWS密钥和实际PUT请求的SHA哈希值。

•此外,从签名中剥离周围的空格,并转义特殊字符(使用quote_plus),以便通过HTTP进行更安全的传输。

•要上载的对象的预期URL是S3存储桶名称和对象名称的组合。

•最后,签名的请求可以与预期的URL一起以JSON格式返回给浏览器。

您可能希望为对象分配另一个自定义名称,而不是使用已命名文件的名称,这对于防止S3存储桶中的意外覆盖非常有用。例如,该名称可能与用户帐户的ID相关。如果没有,您应该提供一些方法来正确引用名称,以防有空格或其他尴尬的字符存在。此外,在此阶段,您可以对上载的文件进行检查,以限制对某些文件类型的访问。例如,可以实现一个简单的检查,只允许.png文件继续这一点。 对于由包含特殊字符的临时签名签名的请求,S3有时可能会响应403(禁止)错误。因此,如上所述,适当地引用签名是很重要的。 最后,在@app.route('/sign_s3/') def sign_s3(): AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID') AWS_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') S3_BUCKET = os.environ.get('S3_BUCKET') object_name = request.args.get('s3_object_name') mime_type = request.args.get('s3_object_type') expires = int(time.time()+10) amz_headers = "x-amz-acl:public-read" put_request = "PUT\n\n%s\n%d\n%s\n/%s/%s" % (mime_type, expires, amz_headers, S3_BUCKET, object_name) signature = base64.encodestring(hmac.new(AWS_SECRET_KEY, put_request, sha1).digest()) signature = urllib.quote_plus(signature.strip()) url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, object_name) return json.dumps({ 'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature), 'url': url }) 中,创建负责在用户上传图像,填写表单并单击提交后接收帐户信息的视图。由于这将是一个POST请求,因此还需要将其定义为“允许的访问方法”。此方法将响应对URL / submit_form /:

的请求
application.py

在此示例中,已调用update_account()函数,但本文未介绍此方法的创建。在您的应用程序中,您应该在此阶段提供一些功能,以允许应用程序将这些帐户详细信息存储在某种形式的数据库中,并正确地将信息与用户帐户详细信息的其余部分相关联。 此外,本文(或配套代码)中尚未定义配置文件页面的URL。理想情况下,例如,在更新帐户后,用户将被重定向回他们自己的个人资料,以便他们可以看到更新的信息。

了解更多信息http://www.tivix.com/blog/easy-user-uploads-with-direct-s3-uploading/