blob-upload-2.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import mimetypes
  2. import datetime
  3. from azure.common import AzureMissingResourceHttpError
  4. from azure.storage.blob import BlobService
  5. from django.core.files.storage import Storage
  6. from django.conf import settings
  7. try:
  8. from django.utils.deconstruct import deconstructible
  9. except ImportError:
  10. # Support for django 1.7 and below
  11. def deconstructible(func):
  12. return func
  13. @deconstructible
  14. class AzureStorage(Storage):
  15. """
  16. Custom file storage system for Azure
  17. """
  18. container = settings.AZURE_STORAGE.get('CONTAINER')
  19. account_name = settings.AZURE_STORAGE.get('ACCOUNT_NAME')
  20. account_key = settings.AZURE_STORAGE.get('ACCOUNT_KEY')
  21. cdn_host = settings.AZURE_STORAGE.get('CDN_HOST')
  22. use_ssl = settings.AZURE_STORAGE.get('USE_SSL')
  23. def __init__(self, account_name=None, account_key=None, container=None,
  24. use_ssl=None, cdn_host=None):
  25. if account_name is not None:
  26. self.account_name = account_name
  27. if account_key is not None:
  28. self.account_key = account_key
  29. if container is not None:
  30. self.container = container
  31. if use_ssl is not None:
  32. self.use_ssl = use_ssl
  33. if cdn_host is not None:
  34. self.cdn_host = cdn_host
  35. def __getstate__(self):
  36. return dict(
  37. account_name=self.account_name,
  38. account_key=self.account_key,
  39. container=self.container,
  40. cdn_host=self.cdn_host,
  41. use_ssl=self.use_ssl
  42. )
  43. def _get_service(self):
  44. if not hasattr(self, '_blob_service'):
  45. self._blob_service = BlobService(
  46. account_name=self.account_name,
  47. account_key=self.account_key,
  48. protocol='https' if self.use_ssl else 'http'
  49. )
  50. return self._blob_service
  51. def _get_properties(self, name):
  52. return self._get_service().get_blob_properties(
  53. container_name=self.container,
  54. blob_name=name
  55. )
  56. def _open(self, name, mode='rb'):
  57. """
  58. Return the AzureStorageFile.
  59. """
  60. from django.core.files.base import ContentFile
  61. contents = self._get_service().get_blob_to_bytes(
  62. container_name=self.container,
  63. blob_name=name
  64. )
  65. return ContentFile(contents)
  66. def _save(self, name, content):
  67. """
  68. Use the Azure Storage service to write ``content`` to a remote file
  69. (called ``name``).
  70. """
  71. content.open()
  72. content_type = None
  73. if hasattr(content.file, 'content_type'):
  74. content_type = content.file.content_type
  75. else:
  76. content_type = mimetypes.guess_type(name)[0]
  77. cache_control = self.get_cache_control(
  78. self.container,
  79. name,
  80. content_type
  81. )
  82. self._get_service().put_block_blob_from_file(
  83. container_name=self.container,
  84. blob_name=name,
  85. stream=content,
  86. x_ms_blob_content_type=content_type,
  87. cache_control=cache_control,
  88. x_ms_blob_cache_control=cache_control
  89. )
  90. content.close()
  91. return name
  92. def listdir(self, path):
  93. """
  94. Lists the contents of the specified path, returning a 2-tuple of lists;
  95. the first item being directories, the second item being files.
  96. """
  97. files = []
  98. if path and not path.endswith('/'):
  99. path = '%s/' % path
  100. path_len = len(path)
  101. if not path:
  102. path = None
  103. blob_list = self._get_service().list_blobs(self.container, prefix=path)
  104. for name in blob_list:
  105. files.append(name[path_len:])
  106. return ([], files)
  107. def exists(self, name):
  108. """
  109. Returns True if a file referenced by the given name already exists in
  110. the storage system, or False if the name is available for a new file.
  111. """
  112. try:
  113. self._get_properties(name)
  114. return True
  115. except AzureMissingResourceHttpError:
  116. return False
  117. def delete(self, name):
  118. """
  119. Deletes the file referenced by name.
  120. """
  121. try:
  122. self._get_service().delete_blob(self.container, name)
  123. except AzureMissingResourceHttpError:
  124. pass
  125. def get_cache_control(self, container, name, content_type):
  126. """
  127. Get the Cache-Control value for a blob, used when saving the blob on
  128. Azure. Returns `None` by default to remain compatible with the
  129. default setting for the SDK.
  130. """
  131. return None
  132. def size(self, name):
  133. """
  134. Returns the total size, in bytes, of the file referenced by name.
  135. """
  136. try:
  137. properties = self._get_properties(name)
  138. return int(properties['content-length'])
  139. except AzureMissingResourceHttpError:
  140. pass
  141. def url(self, name):
  142. """
  143. Returns the URL where the contents of the file referenced by name can
  144. be accessed.
  145. """
  146. blob_url_args = {
  147. 'container_name': self.container,
  148. 'blob_name': name,
  149. }
  150. if self.cdn_host:
  151. # The account name should be built into the cdn hostname
  152. blob_url_args['account_name'] = ''
  153. blob_url_args['host_base'] = self.cdn_host
  154. return self._get_service().make_blob_url(
  155. **blob_url_args
  156. )
  157. def modified_time(self, name):
  158. """
  159. Returns a datetime object containing the last modified time.
  160. """
  161. try:
  162. properties = self._get_properties(name)
  163. return datetime.datetime.strptime(
  164. properties['last-modified'],
  165. '%a, %d %b %Y %H:%M:%S %Z'
  166. )
  167. except AzureMissingResourceHttpError:
  168. pass