Skip to content

Commit fb231b7

Browse files
author
Kevin Brown
committed
Initial commit
This adds the basic storage class along with all of the initial things like requirements and the setup files.
0 parents  commit fb231b7

File tree

6 files changed

+289
-0
lines changed

6 files changed

+289
-0
lines changed

.gitignore

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
*.py[cod]
2+
3+
# C extensions
4+
*.so
5+
6+
# Packages
7+
*.egg
8+
*.egg-info
9+
dist
10+
build
11+
eggs
12+
parts
13+
bin
14+
var
15+
sdist
16+
develop-eggs
17+
.installed.cfg
18+
lib
19+
lib64
20+
21+
# Installer logs
22+
pip-log.txt
23+
24+
# Unit test / coverage reports
25+
.coverage
26+
.tox
27+
nosetests.xml
28+
htmlcov
29+
30+
# Translations
31+
*.mo

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright 2013 Kevin Brown
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

azure_storage/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.0.1"

azure_storage/storage.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
from azure import WindowsAzureMissingResourceError
2+
from azure.storage import BlobService
3+
4+
from django.core.files.storage import Storage
5+
from django.conf import settings
6+
7+
8+
class AzureStorage(Storage):
9+
"""
10+
Custom file storage system for Azure
11+
"""
12+
13+
container = settings.AZURE_STORAGE['CONTAINER']
14+
account_name = settings.AZURE_STORAGE['ACCOUNT_NAME']
15+
account_key = settings.AZURE_STORAGE['ACCOUNT_KEY']
16+
cdn_host = None
17+
use_ssl = settings.AZURE_STORAGE['USE_SSL']
18+
19+
def __init__(self, account_name=None, account_key=None, container=None,
20+
use_ssl=None):
21+
22+
if account_name is not None:
23+
self.account_name = account_name
24+
25+
if account_key is not None:
26+
self.account_key = account_key
27+
28+
if container is not None:
29+
self.container = container
30+
31+
if use_ssl is not None:
32+
self.use_ssl = use_ssl
33+
34+
def __getstate__(self):
35+
return dict(account_name=self.account_name,
36+
account_key=self.account_key, container=self.container,
37+
cdn_host=self.cdn_host, use_ssl=self.use_ssl)
38+
39+
def _get_protocol(self):
40+
if self.use_ssl:
41+
return 'https'
42+
43+
return 'http'
44+
45+
def _get_service(self):
46+
if not hasattr(self, '_blob_service'):
47+
self._blob_service = BlobService(account_name=self.account_name,
48+
account_key=self.account_key, protocol=self._get_protocol())
49+
50+
return self._blob_service
51+
52+
def _get_container_url(self):
53+
if self.cdn_host is not None:
54+
return self.cdn_host
55+
56+
if not hasattr(self, '_container_url'):
57+
self._container_url = '%s://%s/%s' % (self._get_protocol(),
58+
self._get_service()._get_host(), self.container)
59+
60+
return self._container_url
61+
62+
def _get_properties(self, name):
63+
return self._get_service().get_blob_properties(self.container,
64+
name)
65+
66+
def _get_file_obj(self, name):
67+
"""
68+
Helper function to get retrieve the requested Cloud Files Object.
69+
"""
70+
return self._get_service().get_blob(self.container, name)
71+
72+
def _open(self, name, mode='rb'):
73+
"""
74+
Return the AzureStorageFile.
75+
"""
76+
77+
from django.core.files.base import ContentFile
78+
79+
contents = self._get_service().get_blob(self.container, name)
80+
81+
return ContentFile(contents)
82+
83+
def _save(self, name, content):
84+
"""
85+
Use the Azure Storage service to write ``content`` to a remote file
86+
(called ``name``).
87+
"""
88+
import mimetypes
89+
90+
content.open()
91+
92+
content_type = None
93+
94+
if hasattr(content.file, 'content_type'):
95+
content_type = content.file.content_type
96+
else:
97+
content_type = mimetypes.guess_type(name)[0]
98+
99+
if hasattr(content, 'chunks'):
100+
content_str = ''.join(chunk for chunk in content.chunks())
101+
else:
102+
content_str = content.read()
103+
104+
cache_control = self.get_cache_control(self.container, name,
105+
content_type)
106+
107+
self._get_service().put_blob(self.container, name, content_str,
108+
x_ms_blob_type="BlockBlob",
109+
x_ms_blob_content_type=content_type,
110+
cache_control=cache_control,
111+
x_ms_blob_cache_control=cache_control)
112+
113+
content.close()
114+
115+
return name
116+
117+
def listdir(self, path):
118+
"""
119+
Lists the contents of the specified path, returning a 2-tuple of lists;
120+
the first item being directories, the second item being files.
121+
"""
122+
123+
files = []
124+
125+
if path and not path.endswith('/'):
126+
path = '%s/' % path
127+
128+
path_len = len(path)
129+
130+
blob_list = self._get_service().list_blobs(self.container, prefix=path)
131+
132+
for name in blob_list:
133+
files.append(name[path_len:])
134+
135+
return ([], files)
136+
137+
def exists(self, name):
138+
"""
139+
Returns True if a file referenced by the given name already exists in
140+
the storage system, or False if the name is available for a new file.
141+
"""
142+
try:
143+
self._get_properties(name)
144+
145+
return True
146+
except WindowsAzureMissingResourceError:
147+
return False
148+
149+
def delete(self, name):
150+
"""
151+
Deletes the file referenced by name.
152+
"""
153+
154+
try:
155+
self._get_service().delete_blob(self.container, name)
156+
except WindowsAzureMissingResourceError:
157+
pass
158+
159+
def get_cache_control(self, container, name, content_type):
160+
"""
161+
Get the Cache-Control value for a blob, used when saving the blob on
162+
Azure. Returns `None` by default to remain compatible with the
163+
default setting for the SDK.
164+
"""
165+
166+
return None
167+
168+
def size(self, name):
169+
"""
170+
Returns the total size, in bytes, of the file referenced by name.
171+
"""
172+
173+
try:
174+
properties = self._get_properties(name)
175+
176+
return int(properties['content-length'])
177+
except WindowsAzureMissingResourceError:
178+
pass
179+
180+
def url(self, name):
181+
"""
182+
Returns the URL where the contents of the file referenced by name can
183+
be accessed.
184+
"""
185+
186+
return '%s/%s' % (self._get_container_url(), name)
187+
188+
def modified_time(self, name):
189+
"""
190+
Returns a datetime object containing the last modified time.
191+
"""
192+
193+
import datetime
194+
195+
try:
196+
properties = self._get_properties(name)
197+
198+
return datetime.datetime.strptime(properties['last-modified'],
199+
'%a, %d %b %Y %H:%M:%S %Z')
200+
except WindowsAzureMissingResourceError:
201+
pass

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Django>=1.3
2+
azure>=0.7.0

setup.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env python
2+
3+
from setuptools import setup, find_packages
4+
import os
5+
from azure_storage import __version__
6+
7+
PACKAGE_DIR = os.path.abspath(os.path.dirname(__file__))
8+
os.chdir(PACKAGE_DIR)
9+
10+
11+
setup(name='django-azure-storage',
12+
version=__version__,
13+
url="https://github.com/Rediker-Software/django-azure-storage",
14+
author="Kevin Brown",
15+
author_email="[email protected]",
16+
description="Django storage backends for Windows Azure blob storage.",
17+
license="MIT",
18+
packages=find_packages(exclude=["tests*", ]),
19+
include_package_data=True,
20+
install_requires=[
21+
'Django>=1.3',
22+
'azure>=0.7.0',
23+
],
24+
# See http://pypi.python.org/pypi?%3Aaction=list_classifiers
25+
classifiers=[
26+
'Environment :: Web Environment',
27+
'Framework :: Django',
28+
'Intended Audience :: Developers',
29+
'License :: OSI Approved :: MIT License',
30+
'Programming Language :: Python',
31+
'Programming Language :: Python :: 2.6',
32+
'Programming Language :: Python :: 2.7',
33+
]
34+
)

0 commit comments

Comments
 (0)