将媒体从Heroku上传到Amazon S3

4

我是一名有用的助手,可以为您翻译内容。以下是需要翻译的内容:

刚接触Heroku和Amazon S3,还请多多包涵。我已将Django应用程序上传到Heroku,并在用户媒体上传方面遇到了问题。模型如下:

#models.py
class Movie(models.Model):
    title           = models.CharField(max_length = 500)
    poster          = models.ImageField(upload_to = 'storages.backends.s3boto')
    pub_date        = models.DateTimeField(auto_now_add = True)
    author          = models.ForeignKey(User)

海报属性是上传图片的属性。我在本地运行良好,但现在在Heroku上出现错误。所以我添加了“storages.backends.s3boto”,正如许多其他帖子告诉我的那样(不确定是否正确)。
我的Settings.py文件目前看起来很混乱:
#settings.py
PROJECT_ROOT   = os.path.abspath(os.path.dirname(__file__))
PROJECT_DIR    = os.path.join(PROJECT_ROOT, '../qanda')

DEFAULT_FILE_STORAGE    = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE     = 'storages.backends.s3boto.S3BotoStorage'

AWS_ACCESS_KEY_ID         = '****************'
AWS_SECRET_ACCESS_KEY     = '************'
AWS_STORAGE_BUCKET_NAME   = 'mrt-assets'
AWS_PRELOAD_METADATA      = True

MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'qanda/media/movie_posters/)
MEDIA_URL = '/media'
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = 'https://mrt-assets.s3.amazonaws.com/static/'
STATICFILES_DIRS = (os.path.join(PROJECT_DIR, 'static'),)

我的存储桶名字叫做mrt-assets,里面有两个文件夹:static(包含css、js、图片和媒体文件)。目前我不太担心静态文件的问题,因为我已经将CSS / JS文件硬编码到HTML文件中*,但是如何将用户上传的媒体文件(任何类型的图片)放入mrt-assets / media中呢?
*尽管如果有人想帮助处理静态文件也可以。但用户上传的媒体文件更加紧急。
编辑(根据Yuji的评论):
已尝试多种选项,但都无法工作。我回去删除了很多更改,现在这是我的设置。
#settings.py
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
MEDIA_ROOT = 'http://s3.amazonaws.com/mrt-assets/media/'
MEDIA_URL = '/media/'
STATIC_ROOT = 'http://s3.amazonaws.com/mrt-assets/static/'
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
TEMPLATE_DIRS = (os.path.join(PROJECT_ROOT, "templates"),)

#models.py
#same as before, but now have changed the poster directory
poster = models.ImageField().

我不太确定该怎么做,需要将我的Heroku应用连接到S3,以便将用户媒体上传保存在那里。

现在已经将我的S3 Bucket更改为此

mrt-assets
    static
        css
        js
        images
    media
        (empty)

Chris,出了什么错误?我在使用特定的S3Boto时遇到了问题,不得不回退到旧版本以适应Heroku。 - Yuji 'Tomita' Tomita
Yuji,将编辑问题以填写当前状态。提前致谢! - Chris Yin
尝试使用Django S3文件夹存储链接,按照Git中的说明操作,将其添加到INSTALLED_APPS元组中,并添加到requirements.txt文件中,但是遇到了S3文件夹存储的错误。 - Chris Yin
Chris,我仍然没有看到错误信息。当出现错误时,你得到的Python堆栈跟踪是什么?作为将来参考,这在询问有关错误的问题时非常重要。 - Yuji 'Tomita' Tomita
1个回答

5
要将您的媒体上传到<bucket>/media,静态资源上传到<bucket>/static,技巧是为这两种资产类型创建两个不同的默认存储后端,或者使用带有location参数的存储对象显式实例化模型字段。

使用自定义存储实例化模型字段

from storages.backends.s3boto import S3BotoStorage

class Movie(models.Model):
    title = models.CharField(max_length=500)
    poster = models.ImageField(storage=S3BotoStorage(location='media'))
    pub_date = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(User)

S3BotoStorage 指定一个 location,将会给所有上传的文件添加路径前缀。

为媒体和静态资源创建自定义存储后端

这与显式定义带有位置的存储后端几乎相同,但是我们将使用 settings.MEDIA_ROOTsettings.STATIC_ROOT 来全局应用路径前缀。
# settings.py
STATIC_ROOT = '/static/'
MEDIA_ROOT  = '/media/'

DEFAULT_FILE_STORAGE = 'app.storage.S3MediaStorage'
STATICFILES_STORAGE = 'app.storage.S3StaticStorage'


# app/storage.py
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage

class S3MediaStorage(S3BotoStorage):
    def __init__(self, **kwargs):
        kwargs['location'] = kwargs.get('location', 
            settings.MEDIA_ROOT.replace('/', ''))
        super(S3MediaStorage, self).__init__(**kwargs)

class S3StaticStorage(S3BotoStorage):
    def __init__(self, **kwargs):
        kwargs['location'] = kwargs.get('location', 
            settings.STATIC_ROOT.replace('/', ''))
        super(S3StaticStorage, self).__init__(**kwargs)

完善IT

您可以对上述代码进行改进,利用 Heroku配置变量 使其更具可移植性:

# settings.py
import os
STATIC_ROOT = os.environ.get('STATIC_ROOT',
    os.path.join(os.path.dirname(__file__), 'static'))

MEDIA_ROOT = os.environ.get('MEDIA_ROOT',
    os.path.join(os.path.dirname(__file__), 'media'))

DEFAULT_FILE_STORAGE = os.environ.get('DEFAULT_FILE_STORAGE', 
    'django.core.files.storage.FileSystemStorage')

STATICFILES_STORAGE = os.environ.get('STATICFILES_STORAGE', 
    'django.contrib.staticfiles.storage.StaticFilesStorage')

将上述设置与 .env 文件配对,您可以在本地进行开发和测试时使用默认存储后端,在部署到 Heroku 时,您将自动切换到 app.storage.S3MediaStorageapp.storage.S3StaticStorage
# .env
STATIC_ROOT=static
MEDIA_ROOT=media
DEFAULT_FILE_STORAGE=app.storage.S3MediaStorage
STATICFILES_STORAGE=app.storage.S3StaticStorage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接