Как загрузить файлы в корзину S3 из лямбда-развертывания Django с помощью Zappa? - PullRequest
1 голос
/ 12 июня 2019

У меня есть базовое веб-приложение, которое позволяет пользователям загружать файлы. Обработка не требуется, мне просто нужно, чтобы они хранились в определенном хранилище Amazon S3 У меня есть приложение, развернутое с помощью Zappa на AWS Lambda. Функция загрузки документов отлично работает на локальном тестовом сервере, но я не уверен, как заставить его работать на реальном развернутом экземпляре. Я получаю ту же ошибку, если пытаюсь добавить файл через панель администратора. Кто-нибудь знает, что я делаю не так или как это обойти? Я включу трассировку здесь:

File "/var/task/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/var/task/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/var/task/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/var/task/django/views/generic/base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "/var/task/django/contrib/auth/mixins.py" in dispatch
  52.         return super().dispatch(request, *args, **kwargs)

File "/var/task/django/contrib/auth/mixins.py" in dispatch
  85.         return super().dispatch(request, *args, **kwargs)

File "/var/task/django/views/generic/base.py" in dispatch
  97.         return handler(request, *args, **kwargs)

File "/var/task/django/views/generic/edit.py" in post
  172.         return super().post(request, *args, **kwargs)

File "/var/task/django/views/generic/edit.py" in post
  142.             return self.form_valid(form)

File "/var/task/myapp/views.py" in form_valid
  83.         return super(UploadView, self).form_valid(form)

File "/var/task/django/views/generic/edit.py" in form_valid
  125.         self.object = form.save()

File "/var/task/django/forms/models.py" in save
  458.             self.instance.save()

File "/var/task/django/db/models/base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "/var/task/django/db/models/base.py" in save_base
  779.                 force_update, using, update_fields,

File "/var/task/django/db/models/base.py" in _save_table
  870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "/var/task/django/db/models/base.py" in _do_insert
  908.                                using=using, raw=raw)

File "/var/task/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/var/task/django/db/models/query.py" in _insert
  1186.         return query.get_compiler(using=using).execute_sql(return_id)

File "/var/task/django/db/models/sql/compiler.py" in execute_sql
  1334.             for sql, params in self.as_sql():

File "/var/task/django/db/models/sql/compiler.py" in as_sql
  1278.                 for obj in self.query.objs

File "/var/task/django/db/models/sql/compiler.py" in <listcomp>
  1278.                 for obj in self.query.objs

File "/var/task/django/db/models/sql/compiler.py" in <listcomp>
  1277.                 [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]

File "/var/task/django/db/models/sql/compiler.py" in pre_save_val
  1228.         return field.pre_save(obj, add=True)

File "/var/task/django/db/models/fields/files.py" in pre_save
  288.             file.save(file.name, file.file, save=False)

File "/var/task/django/db/models/fields/files.py" in save
  87.         self.name = self.storage.save(name, content, max_length=self.field.max_length)

File "/var/task/django/core/files/storage.py" in save
  51.         name = self.get_available_name(name, max_length=max_length)

File "/var/task/storages/backends/s3boto.py" in get_available_name
  525.         return super(S3BotoStorage, self).get_available_name(name, max_length)

File "/var/task/django/core/files/storage.py" in get_available_name
  75.         while self.exists(name) or (max_length and len(name) > max_length):

File "/var/task/storages/backends/s3boto.py" in exists
  464.         return self._get_key(name) is not None

File "/var/task/storages/backends/s3boto.py" in _get_key
  450.         return self.bucket.get_key(self._encode_name(name))

File "/var/task/boto/s3/bucket.py" in get_key
  193.         key, resp = self._get_key_internal(key_name, headers, query_args_l)

File "/var/task/boto/s3/bucket.py" in _get_key_internal
  232.                     response.status, response.reason, '')

Exception Type: S3ResponseError at /myapp/uploadfile
Exception Value: S3ResponseError: 400 Bad Request

Я пробовал различные конфигурации настроек и не нашел решения. Я постоянно получаю «S3ResponseError: 400 Bad Request», когда я пытаюсь загрузить файл в развертывании Lambda. Я добавил конечную точку S3 в свой VPC, потому что я предполагал, что это может иметь какое-то отношение к доступу в Интернет, но я не получил никаких ошибок тайм-аута, чего я и ожидал бы, если бы это было проблемой. Я также создал файл .boto в главном каталоге моего проекта (где находятся мои zappa_settings.json и manage.py) со следующим:

[Credentials]
aws_access_key_id=***
aws_secret_access_key=****

[s3]
host=s3.us-west-2.amazonaws.com

Мои настройки.py

AWS_S3_HOST = 's3.us-west-2.amazonaws.com'

AWS_S3_ACCESS_KEY_ID = '***'

AWS_S3_SECRET_ACCESS_KEY = '****'

AWS_STORAGE_BUCKET_NAME = 'bucketname'

AWS_QUERYSTRING_AUTH = False

AWS_HEADERS = {'Cache-Control': 'max-age = 86400',}

AWS_STORAGE_REGION = 'us-west-2'

AWS_S3_FILE_OVERWRITE = False

DEFAULT_FILE_STORAGE = "storages.backends.s3boto.S3BotoStorage"

MEDIA_URL = 'http://bucketname.s3.amazonaws.com/'

Форма загрузки моего файла

class CSVUpload(forms.ModelForm):
    class Meta:
        model = UploadedDocument

        fields = ['uploadfile', ]

        labels = {
            'uploadfile': 'Attach CSV or Excel file below (.csv or .xlsx): '
        }

Мой CreateView для модели

class UploadView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    permission_required = 'UploadedDocument.can_add'
    form_class = CSVUpload
    template_name = 'document_upload.html'
    login_url = 'login'
    success_url = 'uploadfile/success'

    def form_valid(self, form):
        form.instance.uploader = self.request.user
        return super(UploadView, self).form_valid(form)

Моя загруженная модель документа

class UploadedDocument(models.Model):
    """A model representing an uploaded document"""
    id = models.AutoField(primary_key=True)
    uploaddate = models.DateTimeField(auto_now_add=True)
    uploadfile = models.FileField(upload_to='files/', null=True, verbose_name="")
    uploader = models.ForeignKey('users.CustomUser', on_delete=models.PROTECT, null=True)

    def __str__(self):
        return str(self.id)

HTML-страница с формой

{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}CSV upload{% endblock title %}
{% load staticfiles %}

{% block content %}
    <div class="jumbotron">
        <h1>Upload CSV file</h1>
        <form enctype="multipart/form-data" method="post">
            {% csrf_token %}
            {{ form|crispy }}
            <button class="btn btn-success" type="submit">Upload</button>
        </form>
    </div>
{% endblock content %}

1 Ответ

0 голосов
/ 12 июня 2019

Попробуйте добавить строку в ваш файл .boto:

[s3]
host=s3.us-west-2.amazonaws.com
use-sigv4 = True

Если вы получите сообщение об ошибке When using SigV4, you must specify a 'host' parameter, это поможет: S3 с использованием boto и SigV4 - отсутствует параметр хоста

...