javascript - 直接到 S3 文件上传 Django 和 Heroku

标签 javascript django heroku amazon-s3

我正在尝试在 Django 中设置直接到 s3 上传以获取更大的音频文件。 我基本上遵循了 Heroku 的 Direct To S3 教程 https://devcenter.heroku.com/articles/s3-upload-python它更适合 Flask。我也找不到 Django 调试所指的获取请求。预先感谢您的帮助。

我收到以下错误:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/sign-s3/?file_name=piano.wav&file_type=audio/wav

Django Version: 2.0
Python Version: 3.6.5
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sitemaps',
 'django.contrib.sites',
 'crispy_forms',
 'tinymce',
 'storages',
 'ckeditor',
 'ckeditor_uploader',
 'main',
 'contact',
 'accounts',
 'events',
 'news',
 'project_settings',
 'django_countries',
 'publications',
 'event_tracker',
 'event_signup']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Users/Tommy/anaconda3/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  35.             response = get_response(request)

File "/Users/Tommy/anaconda3/lib/python3.6/site-packages/django/utils/deprecation.py" in __call__
  97.             response = self.process_response(request, response)

File "/Users/Tommy/anaconda3/lib/python3.6/site-packages/django/middleware/clickjacking.py" in process_response
  26.         if response.get('X-Frame-Options') is not None:

Exception Type: AttributeError at /sign-s3/
Exception Value: 'str' object has no attribute 'get'

Views.py 文件:

def committee_new_podcast(request, id):
    template = "main/add_podcast.html"

    committee = get_object_or_404(Committee, comm_id=id)

    if request.user.is_authenticated:
        if Member.objects.filter(user=request.user).exists():
            member = Member.objects.get(user=request.user)

            if CommitteeMember.objects.filter(Q(is_chair=True) | Q(is_deputy=True)).filter(abila=member, comm=committee.comm_id) or request.user.is_staff:
                if request.method == 'POST':
                    form = CommitteePodcastForm(request.POST, request.FILES)

                    if form.is_valid():
                        instance = form.save(commit=False)
                        instance.comm_id = committee
                        instance.member = member
                        instance.sound = request.form['avatar-url']
                        instance.save()
                        messages.success(request, 'Committee Podcast Was Created',
                                         "alert alert-success alert-dismissible")

                else:
                    form = CommitteePodcastForm()

            else:
                form = ''
                messages.success(request, 'You must be a chair or deputy to access this page.',
                                 "alert alert-danger alert-dismissible")
        elif request.user.is_staff:
            if request.method == 'POST':
                form = CommitteePodcastForm(request.POST, request.FILES)

                if form.is_valid():
                    instance = form.save(commit=False)
                    instance.comm_id = committee
                    instance.save()
                    messages.success(request, 'Committee Podcast Was Created',
                                     "alert alert-success alert-dismissible")
            else:
                form = CommitteePodcastForm()
        else:
            form = ''
            pass
    else:
        form = ''
        messages.success(request, 'You must be logged in to access this page.',
                         "alert alert-danger alert-dismissible")

    context = {
        'committee': committee,
        'form': form,
    }

    return render(request, template, context)


def sign_s3(request):
    S3_BUCKET = settings.AWS_STORAGE_BUCKET_NAME

    file_name = request.GET.get('file_name')
    file_type = request.GET.get('file_type')

    s3 = boto3.client('s3')

    presigned_post = s3.generate_presigned_post(
        Bucket = S3_BUCKET,
        Key = file_name,
        Fields = {"acl": "public-read", "Content-Type": file_type},
        Conditions = [
            {'acl': "public-read"},
            {"Content-Type": file_type}
        ],
        ExpiresIn = 3600
    )

    return json.dumps({
        'data': presigned_post,
        'url': 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, file_name),
    })

Javascript:

<script>
    (function() {
        document.getElementById('file_input').onchange = function(){
            var files = document.getElementById('file_input').files;
            var file = files[0];
            if(!file){
                return alert("No file selected.");
            }
            getSignedRequest(file);
        }
    })();

    function getSignedRequest(file){
        var xhr = new XMLHttpRequest();
        xhr.open("GET",  "/sign-s3?file_name="+file.name+"&file_type="+file.type);
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status === 200){
                    var response = JSON.parse(xhr.responseText);
                    uploadFile(file, response.data, response.url);
                }
                else{
                    alert("Could not get signed URL.");
                }
            }
        }
        xhr.send();
    }

    function uploadFile(file, s3Data, url){
        var xhr = new XMLHttpRequest();
        xhr.open("POST", s3Data.url);

        var postData = new FormData();
        for(key in s3Data.fields){
            postData.append(key, s3Data.fields[key]);
        }
        postData.append('file', file);

        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4){
                if(xhr.status === 200 || xhr.status == 204){
                    document.getElementById("sound-url").value = url;
                }
                else {
                    alert("Could not upload file.");
                }
            }
        }
        xhr.send(postData)
    }
</script>

最佳答案

我明白了,我应该一直使用 HttpResponse 来返回 JSON 数据。

def sign_s3(request):
    S3_BUCKET = settings.AWS_STORAGE_BUCKET_NAME

    file_name = request.GET.get('file_name')
    file_type = request.GET.get('file_type')

    s3 = boto3.client('s3')

    presigned_post = s3.generate_presigned_post(
        Bucket = S3_BUCKET,
        Key = file_name,
        Fields = {"acl": "public-read", "Content-Type": file_type},
        Conditions = [
            {'acl': "public-read"},
            {"Content-Type": file_type}
        ],
        ExpiresIn = 3600
    )

    data = json.dumps({
        'data': presigned_post,
        'url': 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, file_name),
    })

    return HttpResponse(data, content_type='json')

关于javascript - 直接到 S3 文件上传 Django 和 Heroku,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51218970/

相关文章:

javascript - D3 多线图 x 轴返回 NaN

javascript - Ajax GET 请求的 XSS 问题

javascript - jQuery - 获取具有特定类的选中复选框的值

python - 返回带有序列化程序列表的响应 Django REST Framework

.net - Heroku 应用程序在 TLS v1.0/1.1 生命周期结束后无法使用 https

javascript - 希望通过单击按钮进行搜索,而不是通过键盘输入进行搜索。 PHP 和 MYSQL

Django json 策略?

node.js - 使用 Node 和 Heroku 进行负载平衡

ruby-on-rails - 推送到 heroku 的应用程序仍然显示标准索引页面

django - 如何在django列表中添加序列号?