Django仅在生产环境中使用私有S3存储

时间:2019-12-21 15:49:08

标签: python django amazon-s3 django-rest-framework django-storage

我已将django REST API设置为在调试模式下使用本地存储,在生产环境下使用S3存储。这对于公共文件非常有效,因为我像这样覆盖DEFAULT_FILE_STORAGE

if IS_DEBUG:
    DEFAULT_FILE_STORAGE = 'api.storage_backends.PublicMediaStorage'

,每个FileField都会自动使用它。现在,我想以相同的方式使用私有S3存储,但是由于必须显式定义存储(FileField(storage=PrivateMediaStorage())),因此始终使用S3存储。

在调试模式下,如何使用本地存储而不是S3存储?

PS:我已经考虑过根据DEBUG模式将模型更改为使用FileField有无显式存储。这并不能完全解决我的问题,因为我的迁移是在DEBUG模式下创建的,因此始终包含没有私有存储类的模型。

2 个答案:

答案 0 :(得分:3)

听起来这里最棘手的部分是在单个项目中同时具有 public private 媒体存储。

下面的示例假定您使用的是django storages,但是无论如何,该技术都可以工作。

通过扩展S3BotoStorage类来定义私有存储。

如果使用S3,则最好将 private public public存储在不同的S3存储桶中。此自定义存储允许您通过设置指定此参数。

# yourapp.custom_storage.py

from django.conf import settings
from django.core.files.storage import get_storage_class
from storages.backends.s3boto import S3BotoStorage

class S3PrivateStorage(S3BotoStorage):
    """
    Optional   
    """
    default_acl = "private"               # this does the trick

    def __init__(self):
        super(S3PrivateStorage, self).__init__()
        self.bucket_name = settings.S3_PRIVATE_STORAGE_BUCKET_NAME


# important
private_storage_class = get_storage_class(settings.PRIVATE_FILE_STORAGE)

private_storage = private_storage_class() # instantiate the storage

重要的部分是此文件的最后两行-它声明private_storage供您的FileField使用:

from yourappp.custom_storage import private_storage
...
class YourModel(Model):

    the_file = models.FileField(
                   upload_to=..., 
                   storage=private_storage)
...

最后,在您的设置文件中,应该这样做。

# settings.py

if DEBUG:
    # In debug mode, store everything on the filestystem
    DEFAULT_FILE_STORAGE = 'django.files.storage.FileSystemStorage'
    PRIVATE_FILE_STORAGE = 'django.files.storage.FileSystemStorage'
else:
    # In production store public things using S3BotoStorage and private things
    # in a custom storage
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    PRIVATE_FILE_STORAGE = 'yourapp.custom_storage.S3PrivateStorage'

作为最后一条未经请求的建议:将存储设置与 DEBUG模式脱钩并允许在环境变量中指定上述所有参数通常很有用。在某些时候,您可能希望使用类似生产的存储配置以调试模式运行应用程序。

答案 1 :(得分:2)

最好的解决方案是使用 FileField 而不使用显式的 storage 类。

# settings.py

if DEBUG:
    DEFAULT_FILE_STORAGE = 'api.storage_backends.PublicMediaStorage'
else:
    DEFAULT_FILE_STORAGE = 'api.storage_backends.PrivateMediaStorage'


# models.py
class Foo(models.Model):
    file = models.FileField() # without storage

在文件上传过程中,Django将以 lazy 的方式调用DEFAULT_FILE_STORAGE类。

注意

这些设置不会使用 storage 参数

创建迁移文件

UPDATE-1

如果您想进一步控制存储,请创建自己的自定义文件字段并在模型中进行接线

def get_storage():
    """
    Change this function to whatever way as you need
    """
    from api.storage_backends import PublicMediaStorage, PrivateMediaStorage
    if DEBUG:
        return PublicMediaStorage()
    else:
        return PrivateMediaStorage()


class CustomFileField(models.FileField):
    def __init__(self, *args, **kwargs):
        kwargs['storage'] = get_storage() # calling external function
        super().__init__(*args, **kwargs)


class Foo(models.Model):
    file = CustomFileField() # use custom filefield here