直接到S3文件上传Django和Heroku

时间:2018-07-07 00:18:47

标签: javascript django heroku amazon-s3

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

我收到以下错误:

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>

1 个答案:

答案 0 :(得分:2)

我知道我应该一直使用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')