我已将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模式下创建的,因此始终包含没有私有存储类的模型。
答案 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
参数
如果您想进一步控制存储,请创建自己的自定义文件字段并在模型中进行接线
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