123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- import mimetypes
- import datetime
- from azure.common import AzureMissingResourceHttpError
- from azure.storage.blob import BlobService
- from django.core.files.storage import Storage
- from django.conf import settings
- try:
- from django.utils.deconstruct import deconstructible
- except ImportError:
- # Support for django 1.7 and below
- def deconstructible(func):
- return func
- @deconstructible
- class AzureStorage(Storage):
- """
- Custom file storage system for Azure
- """
- container = settings.AZURE_STORAGE.get('CONTAINER')
- account_name = settings.AZURE_STORAGE.get('ACCOUNT_NAME')
- account_key = settings.AZURE_STORAGE.get('ACCOUNT_KEY')
- cdn_host = settings.AZURE_STORAGE.get('CDN_HOST')
- use_ssl = settings.AZURE_STORAGE.get('USE_SSL')
- def __init__(self, account_name=None, account_key=None, container=None,
- use_ssl=None, cdn_host=None):
- if account_name is not None:
- self.account_name = account_name
- if account_key is not None:
- self.account_key = account_key
- if container is not None:
- self.container = container
- if use_ssl is not None:
- self.use_ssl = use_ssl
- if cdn_host is not None:
- self.cdn_host = cdn_host
- def __getstate__(self):
- return dict(
- account_name=self.account_name,
- account_key=self.account_key,
- container=self.container,
- cdn_host=self.cdn_host,
- use_ssl=self.use_ssl
- )
- def _get_service(self):
- if not hasattr(self, '_blob_service'):
- self._blob_service = BlobService(
- account_name=self.account_name,
- account_key=self.account_key,
- protocol='https' if self.use_ssl else 'http'
- )
- return self._blob_service
- def _get_properties(self, name):
- return self._get_service().get_blob_properties(
- container_name=self.container,
- blob_name=name
- )
- def _open(self, name, mode='rb'):
- """
- Return the AzureStorageFile.
- """
- from django.core.files.base import ContentFile
- contents = self._get_service().get_blob_to_bytes(
- container_name=self.container,
- blob_name=name
- )
- return ContentFile(contents)
- def _save(self, name, content):
- """
- Use the Azure Storage service to write ``content`` to a remote file
- (called ``name``).
- """
-
- content.open()
- content_type = None
- if hasattr(content.file, 'content_type'):
- content_type = content.file.content_type
- else:
- content_type = mimetypes.guess_type(name)[0]
- cache_control = self.get_cache_control(
- self.container,
- name,
- content_type
- )
- self._get_service().put_block_blob_from_file(
- container_name=self.container,
- blob_name=name,
- stream=content,
- x_ms_blob_content_type=content_type,
- cache_control=cache_control,
- x_ms_blob_cache_control=cache_control
- )
- content.close()
- return name
- def listdir(self, path):
- """
- Lists the contents of the specified path, returning a 2-tuple of lists;
- the first item being directories, the second item being files.
- """
- files = []
- if path and not path.endswith('/'):
- path = '%s/' % path
- path_len = len(path)
- if not path:
- path = None
- blob_list = self._get_service().list_blobs(self.container, prefix=path)
- for name in blob_list:
- files.append(name[path_len:])
- return ([], files)
- def exists(self, name):
- """
- Returns True if a file referenced by the given name already exists in
- the storage system, or False if the name is available for a new file.
- """
- try:
- self._get_properties(name)
- return True
- except AzureMissingResourceHttpError:
- return False
- def delete(self, name):
- """
- Deletes the file referenced by name.
- """
- try:
- self._get_service().delete_blob(self.container, name)
- except AzureMissingResourceHttpError:
- pass
- def get_cache_control(self, container, name, content_type):
- """
- Get the Cache-Control value for a blob, used when saving the blob on
- Azure. Returns `None` by default to remain compatible with the
- default setting for the SDK.
- """
- return None
- def size(self, name):
- """
- Returns the total size, in bytes, of the file referenced by name.
- """
- try:
- properties = self._get_properties(name)
- return int(properties['content-length'])
- except AzureMissingResourceHttpError:
- pass
- def url(self, name):
- """
- Returns the URL where the contents of the file referenced by name can
- be accessed.
- """
- blob_url_args = {
- 'container_name': self.container,
- 'blob_name': name,
- }
- if self.cdn_host:
- # The account name should be built into the cdn hostname
- blob_url_args['account_name'] = ''
- blob_url_args['host_base'] = self.cdn_host
- return self._get_service().make_blob_url(
- **blob_url_args
- )
- def modified_time(self, name):
- """
- Returns a datetime object containing the last modified time.
- """
- try:
- properties = self._get_properties(name)
- return datetime.datetime.strptime(
- properties['last-modified'],
- '%a, %d %b %Y %H:%M:%S %Z'
- )
- except AzureMissingResourceHttpError:
- pass
|