首页 > 解决方案 > 使用 python eve 将文件上传到 Amazon S3

问题描述

我正在尝试将图像上传到 S3 存储桶。我提到了eve 文档和这个 git repo。我试图通过以下方式做到这一点。

#/ run.py
```python
from eve import Eve
from flask_sslify import SSLify
import os
from eve.io.media import MediaStorage
from flask.app import Flask
from flask import current_app
import boto3
from botocore.exceptions import ClientError
from s3_out import S3Out
from bson.objectid import ObjectId

BUCKET = 'bucket'
AWS_REGION = 'region'
AWS_KEY = 'key'
AWS_SECRET = 'secret'

class S3MediaStorage(MediaStorage):
    """
    MediaStorage implementation compatible with AWS S3 service.
    """

    def __init__(self, app=None):
        super(S3MediaStorage, self).__init__(app)
        self.validate()
        self.s3 = boto3.client('s3', aws_access_key_id=AWS_KEY,
                           aws_secret_access_key=AWS_SECRET,
                           region_name=AWS_REGION)

    def validate(self):
    """ Make sure that the application is an eve application.
    instance.
    """
        if self.app is None:
            raise TypeError('Application object cannot be None')

        if not isinstance(self.app, Flask):
            raise TypeError('Application object must be a Eve application')

    def exists(self, id_or_filename, resource=None):
        try:
            self.s3.get_object(Bucket=BUCKET, Key=id_or_filename)
        except ClientError as ex:
            if ex.response['Error']['Code'] == 'NoSuchKey':
                return False
        return True

    def get(self, id_or_filename, resource=None):
        try:
            s3_object = self.s3.get_object(
                Bucket=BUCKET, Key=str(id_or_filename))
        except ClientError as ex:
            return None

        length = s3_object.get('ContentLength', 1500)
        content_type = s3_object.get('ContentType', 'image/jpg')
        last_modified = s3_object.get('LastModified', None)

        assert 'Body' in s3_object
        response = S3Out(s3_object['Body'].read(),
                     content_type, last_modified, length)
        return response

    def delete(self, id_or_filename, resource=None):
        return self.s3.delete_object(Bucket=BUCKET, Key=id_or_filename)

    def put(self, content, filename=None, content_type=None, resource=None):
        _id = str(ObjectId())
        self.s3.upload_fileobj(content,  _id, BUCKET,  ExtraArgs={
                           'ContentType': content_type})
        return _id


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

来自 repo 的 s3_out.py 文件

#/s3_out.py
from datetime import datetime
from io import BytesIO


class S3Out(object):
    def __init__(self, file: bytes, content_type: str, upload_date: datetime, length: int):
        self.file = file
        self.content_type = content_type
        self.upload_date = upload_date
        self.length = length

    def __iter__(self):
        return BytesIO(self.file)

    def read(self):
        with open(self.file, mode='rb') as file:
            f = file.read()
            return bytearray(f)

我的 settings.py 文件

EXTENDED_MEDIA_INFO = ['content_type', 'name', 'length']
RETURN_MEDIA_AS_BASE64_STRING = False
RETURN_MEDIA_AS_URL = True
# MEDIA_BASE_URL = 'https://s3-us-west-2.amazonaws.com'
MEDIA_ENDPOINT = 'media'

logos = {
    'logo': {'type': 'media'}
}

DOMAIN = {
    'logos': logos,
}

我收到以下错误

    [2020-08-13 16:29:56,808] ERROR in post: maximum recursion depth exceeded while calling a Python object
Traceback (most recent call last):
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\eve\methods\post.py", line 223, in post_internal
    doc_issues = validator.errors
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\cerberus\validator.py", line 464, in errors
    return self.error_handler(self._errors)
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\cerberus\errors.py", line 493, in __call__
    self.extend(errors)
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\cerberus\errors.py", line 397, in extend
    self.add(error)
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\cerberus\errors.py", line 510, in add
    error = deepcopy(error)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 150, in deepcopy
    y = copier(x, memo)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
File "C:\Users\D.Vishal\Anaconda3\lib\copy.py", line 281, in _reconstruct
    if hasattr(y, '__setstate__'):
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\werkzeug\datastructures.py", line 2822, in __getattr__
    return getattr(self.stream, name)
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\werkzeug\datastructures.py", line 2822, in __getattr__
    return getattr(self.stream, name)
File "C:\Users\D.Vishal\Anaconda3\lib\site-packages\werkzeug\datastructures.py", line 2822, in __getattr__
    return getattr(self.stream, name)
[Previous line repeated 477 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

我对邮递员的要求 在此处输入图像描述

我不知道我是否遗漏了什么或做错了什么。任何帮助都会很棒。提前致谢。

标签: pythonamazon-s3eve

解决方案


推荐阅读