Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,18 @@ Use the following settings to configure AliCloud OSS file storage.
# Refer https://www.alibabacloud.com/help/zh/doc-detail/31837.htm for OSS Region & Endpoint
OSS_ENDPOINT = <Your access endpoint>

# The default location for your files
MEDIA_URL = '/media/'
# The default location for your project
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# The default location for your media files
# In both cases, your media files will be put into OSS://<your_bucket>/media/
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_ROOT = "/media/"

# Your can use this MEDIA_URL in your django templates
MEDIA_URL = "http://<your-bucket>.<your-endpoint>.aliyuncs.com/media/"
# Or your custom domain MEDIA_URL
MEDIA_URL = "http://<your-custom-domain>/media/"

Staticfiles storage settings
============================
Expand All @@ -82,7 +92,14 @@ All of the file storage settings are available for the staticfiles storage.
.. code-block:: bash

# The default location for your static files
STATIC_URL = '/static/'
# In both case, your static files will be put into OSS://<your_bucket>/static/
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_ROOT = "/static/"

# Your can use this STATIC_URL in your django templates
STATIC_URL = 'http://<your-bucket>.<your-endpoint>.aliyuncs.com/static/'
# Or your custom domain STATIC_URL
STATIC_URL = "http://<your-custom-domain>/static/"

staticfiles provides command 'collectstatic'. Run following command to collect all sub-folder 'static' of each app
and upload to STATIC_URL.
Expand Down
2 changes: 1 addition & 1 deletion django_oss_storage/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.1.1'
__version__ = '1.1.2'
44 changes: 35 additions & 9 deletions django_oss_storage/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ def _normalize_endpoint(endpoint):
else:
return endpoint


class OssError(Exception):
def __init__(self, value):
self.value = value

def __str__(self):
return repr(self.value)


@deconstructible
class OssStorage(Storage):
"""
Expand All @@ -61,7 +63,8 @@ def __init__(self, access_key_id=None, access_key_secret=None, end_point=None, b
self.access_key_secret = access_key_secret if access_key_secret else _get_config('OSS_ACCESS_KEY_SECRET')
self.end_point = _normalize_endpoint(end_point if end_point else _get_config('OSS_ENDPOINT'))
self.bucket_name = bucket_name if bucket_name else _get_config('OSS_BUCKET_NAME')
self.expire_time = expire_time if expire_time else int(_get_config('OSS_EXPIRE_TIME', default=60*60*24*30))
self.expire_time = expire_time if expire_time else int(
_get_config('OSS_EXPIRE_TIME', default=60 * 60 * 24 * 30))

self.auth = Auth(self.access_key_id, self.access_key_secret)
self.service = Service(self.auth, self.end_point)
Expand All @@ -80,8 +83,9 @@ def _get_key_name(self, name):
input : test.txt
output : media/test.txt
"""
# Store filenames with forward slashes, even on Windows.
# urljoin won't work if name is absolute path
name = name.lstrip('/')
name = name.replace('\\', '/').lstrip('/')

base_path = force_text(self.location)
final_path = urljoin(base_path + "/", name)
Expand All @@ -91,10 +95,14 @@ def _get_key_name(self, name):
if final_path.endswith('/') and not name.endswith('/'):
name += '/'

# Store filenames with forward slashes, even on Windows.
# OSS does not work with name starts with splashes
name = name.replace('\\', '/').lstrip('/')

if six.PY2:
name = name.encode('utf-8')
# Store filenames with forward slashes, even on Windows.
return name.replace('\\', '/')

return name

def _open(self, name, mode='rb'):
logger().debug("name: %s, mode: %s", name, mode)
Expand All @@ -105,7 +113,7 @@ def _open(self, name, mode='rb'):
logger().debug("target name: %s", target_name)
try:
# Load the key into a temporary file
tmpf = SpooledTemporaryFile(max_size=10*1024*1024) # 10MB
tmpf = SpooledTemporaryFile(max_size=10 * 1024 * 1024) # 10MB
obj = self.bucket.get_object(target_name)
logger().info("content length: %d, requestid: %s", obj.content_length, obj.request_id)
if obj.content_length is None:
Expand Down Expand Up @@ -209,9 +217,9 @@ def listdir(self, name):
def url(self, name):
key = self._get_key_name(name)
str = self.bucket.sign_url('GET', key, expires=self.expire_time)
if self.bucket_acl != BUCKET_ACL_PRIVATE :
if self.bucket_acl != BUCKET_ACL_PRIVATE:
idx = str.find('?')
if idx > 0:
if idx > 0:
str = str[:idx].replace('%2F', '/')
return str

Expand All @@ -227,16 +235,34 @@ def delete_with_slash(self, dirname):
logger().debug("delete name: %s", name)
result = self.bucket.delete_object(name)

@classmethod
def get_relative_location(cls, location):
"""get relative location for OSS storage. since Django requires settings.MEDIA_ROOT and settings.STATIC_ROOT
to be absolute paths, we provide this method to calculate the essential relative path.
Most of the case there is a BASE_DIR or ROOT_DIR setting as the root directory of the project, we calculate
relative path based on these two settings if they exist."""
base_dir = None
if hasattr(settings, "BASE_DIR"): #
base_dir = settings.BASE_DIR
elif hasattr(settings, "ROOT_DIR"):
base_dir = settings.ROOT_DIR
if base_dir is None:
return location
if not location.startswith(base_dir):
return location
return location[len(base_dir):]


class OssMediaStorage(OssStorage):
def __init__(self):
self.location = settings.MEDIA_URL
self.location = OssStorage.get_relative_location(settings.MEDIA_ROOT)
logger().debug("locatin: %s", self.location)
super(OssMediaStorage, self).__init__()


class OssStaticStorage(OssStorage):
def __init__(self):
self.location = settings.STATIC_URL
self.location = OssStorage.get_relative_location(settings.STATIC_ROOT)
logger().info("locatin: %s", self.location)
super(OssStaticStorage, self).__init__()

Expand Down
12 changes: 12 additions & 0 deletions tests/django-oss-storage-test/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
fh.setFormatter(formatter)
logger.addHandler(fh)


class TestOssStorage(SimpleTestCase):

@contextmanager
Expand All @@ -50,6 +51,17 @@ def create_dir(self, name="testdir/", storage=default_storage):
finally:
pass

def test_get_relative_paths(self):
self.assertEqual(
OssStorage.get_relative_location("/home/user_test/project/test1"),
"/home/user_test/project/test1")
with self.settings(BASE_DIR="/home/user_test/project/"):
self.assertEqual(OssStorage.get_relative_location("/test2"), "/test2")
self.assertEqual(OssStorage.get_relative_location("/home/user_test/project/test3"), "/test3")
self.assertEqual(
OssStorage.get_relative_location("/home2/user_test/project/test4"),
"/home2/user_test/project/test4")

def test_settings_mported(self):
# Make sure bucket 'test-tmp-b1' exist under your OSS account
#self.assertEqual(settings.OSS_BUCKET_NAME, "test-tmp-b1")
Expand Down