PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/servicios_web/gae/django-guestbook/src/django/core/files/storage.py

https://github.com/enlaces/curso_python_dga_11
Python | 275 lines | 240 code | 10 blank | 25 comment | 4 complexity | 7d31713aea1eae7a8fb5f2c3103b8d7d MD5 | raw file
  1. import os
  2. import errno
  3. import urlparse
  4. import itertools
  5. from datetime import datetime
  6. from django.conf import settings
  7. from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
  8. from django.core.files import locks, File
  9. from django.core.files.move import file_move_safe
  10. from django.utils.encoding import force_unicode
  11. from django.utils.functional import LazyObject
  12. from django.utils.importlib import import_module
  13. from django.utils.text import get_valid_filename
  14. from django.utils._os import safe_join
  15. __all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage')
  16. class Storage(object):
  17. """
  18. A base storage class, providing some default behaviors that all other
  19. storage systems can inherit or override, as necessary.
  20. """
  21. # The following methods represent a public interface to private methods.
  22. # These shouldn't be overridden by subclasses unless absolutely necessary.
  23. def open(self, name, mode='rb', mixin=None):
  24. """
  25. Retrieves the specified file from storage, using the optional mixin
  26. class to customize what features are available on the File returned.
  27. """
  28. file = self._open(name, mode)
  29. if mixin:
  30. # Add the mixin as a parent class of the File returned from storage.
  31. file.__class__ = type(mixin.__name__, (mixin, file.__class__), {})
  32. return file
  33. def save(self, name, content):
  34. """
  35. Saves new content to the file specified by name. The content should be a
  36. proper File object, ready to be read from the beginning.
  37. """
  38. # Get the proper name for the file, as it will actually be saved.
  39. if name is None:
  40. name = content.name
  41. name = self.get_available_name(name)
  42. name = self._save(name, content)
  43. # Store filenames with forward slashes, even on Windows
  44. return force_unicode(name.replace('\\', '/'))
  45. # These methods are part of the public API, with default implementations.
  46. def get_valid_name(self, name):
  47. """
  48. Returns a filename, based on the provided filename, that's suitable for
  49. use in the target storage system.
  50. """
  51. return get_valid_filename(name)
  52. def get_available_name(self, name):
  53. """
  54. Returns a filename that's free on the target storage system, and
  55. available for new content to be written to.
  56. """
  57. dir_name, file_name = os.path.split(name)
  58. file_root, file_ext = os.path.splitext(file_name)
  59. # If the filename already exists, add an underscore and a number (before
  60. # the file extension, if one exists) to the filename until the generated
  61. # filename doesn't exist.
  62. count = itertools.count(1)
  63. while self.exists(name):
  64. # file_ext includes the dot.
  65. name = os.path.join(dir_name, "%s_%s%s" % (file_root, count.next(), file_ext))
  66. return name
  67. def path(self, name):
  68. """
  69. Returns a local filesystem path where the file can be retrieved using
  70. Python's built-in open() function. Storage systems that can't be
  71. accessed using open() should *not* implement this method.
  72. """
  73. raise NotImplementedError("This backend doesn't support absolute paths.")
  74. # The following methods form the public API for storage systems, but with
  75. # no default implementations. Subclasses must implement *all* of these.
  76. def delete(self, name):
  77. """
  78. Deletes the specified file from the storage system.
  79. """
  80. raise NotImplementedError()
  81. def exists(self, name):
  82. """
  83. Returns True if a file referened by the given name already exists in the
  84. storage system, or False if the name is available for a new file.
  85. """
  86. raise NotImplementedError()
  87. def listdir(self, path):
  88. """
  89. Lists the contents of the specified path, returning a 2-tuple of lists;
  90. the first item being directories, the second item being files.
  91. """
  92. raise NotImplementedError()
  93. def size(self, name):
  94. """
  95. Returns the total size, in bytes, of the file specified by name.
  96. """
  97. raise NotImplementedError()
  98. def url(self, name):
  99. """
  100. Returns an absolute URL where the file's contents can be accessed
  101. directly by a Web browser.
  102. """
  103. raise NotImplementedError()
  104. def accessed_time(self, name):
  105. """
  106. Returns the last accessed time (as datetime object) of the file
  107. specified by name.
  108. """
  109. raise NotImplementedError()
  110. def created_time(self, name):
  111. """
  112. Returns the creation time (as datetime object) of the file
  113. specified by name.
  114. """
  115. raise NotImplementedError()
  116. def modified_time(self, name):
  117. """
  118. Returns the last modified time (as datetime object) of the file
  119. specified by name.
  120. """
  121. raise NotImplementedError()
  122. class FileSystemStorage(Storage):
  123. """
  124. Standard filesystem storage
  125. """
  126. def __init__(self, location=None, base_url=None):
  127. if location is None:
  128. location = settings.MEDIA_ROOT
  129. if base_url is None:
  130. base_url = settings.MEDIA_URL
  131. self.location = os.path.abspath(location)
  132. self.base_url = base_url
  133. def _open(self, name, mode='rb'):
  134. return File(open(self.path(name), mode))
  135. def _save(self, name, content):
  136. full_path = self.path(name)
  137. directory = os.path.dirname(full_path)
  138. if not os.path.exists(directory):
  139. os.makedirs(directory)
  140. elif not os.path.isdir(directory):
  141. raise IOError("%s exists and is not a directory." % directory)
  142. # There's a potential race condition between get_available_name and
  143. # saving the file; it's possible that two threads might return the
  144. # same name, at which point all sorts of fun happens. So we need to
  145. # try to create the file, but if it already exists we have to go back
  146. # to get_available_name() and try again.
  147. while True:
  148. try:
  149. # This file has a file path that we can move.
  150. if hasattr(content, 'temporary_file_path'):
  151. file_move_safe(content.temporary_file_path(), full_path)
  152. content.close()
  153. # This is a normal uploadedfile that we can stream.
  154. else:
  155. # This fun binary flag incantation makes os.open throw an
  156. # OSError if the file already exists before we open it.
  157. fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
  158. try:
  159. locks.lock(fd, locks.LOCK_EX)
  160. for chunk in content.chunks():
  161. os.write(fd, chunk)
  162. finally:
  163. locks.unlock(fd)
  164. os.close(fd)
  165. except OSError, e:
  166. if e.errno == errno.EEXIST:
  167. # Ooops, the file exists. We need a new file name.
  168. name = self.get_available_name(name)
  169. full_path = self.path(name)
  170. else:
  171. raise
  172. else:
  173. # OK, the file save worked. Break out of the loop.
  174. break
  175. if settings.FILE_UPLOAD_PERMISSIONS is not None:
  176. os.chmod(full_path, settings.FILE_UPLOAD_PERMISSIONS)
  177. return name
  178. def delete(self, name):
  179. name = self.path(name)
  180. # If the file exists, delete it from the filesystem.
  181. if os.path.exists(name):
  182. os.remove(name)
  183. def exists(self, name):
  184. return os.path.exists(self.path(name))
  185. def listdir(self, path):
  186. path = self.path(path)
  187. directories, files = [], []
  188. for entry in os.listdir(path):
  189. if os.path.isdir(os.path.join(path, entry)):
  190. directories.append(entry)
  191. else:
  192. files.append(entry)
  193. return directories, files
  194. def path(self, name):
  195. try:
  196. path = safe_join(self.location, name)
  197. except ValueError:
  198. raise SuspiciousOperation("Attempted access to '%s' denied." % name)
  199. return os.path.normpath(path)
  200. def size(self, name):
  201. return os.path.getsize(self.path(name))
  202. def url(self, name):
  203. if self.base_url is None:
  204. raise ValueError("This file is not accessible via a URL.")
  205. return urlparse.urljoin(self.base_url, name).replace('\\', '/')
  206. def accessed_time(self, name):
  207. return datetime.fromtimestamp(os.path.getatime(self.path(name)))
  208. def created_time(self, name):
  209. return datetime.fromtimestamp(os.path.getctime(self.path(name)))
  210. def modified_time(self, name):
  211. return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
  212. def get_storage_class(import_path=None):
  213. if import_path is None:
  214. import_path = settings.DEFAULT_FILE_STORAGE
  215. try:
  216. dot = import_path.rindex('.')
  217. except ValueError:
  218. raise ImproperlyConfigured("%s isn't a storage module." % import_path)
  219. module, classname = import_path[:dot], import_path[dot+1:]
  220. try:
  221. mod = import_module(module)
  222. except ImportError, e:
  223. raise ImproperlyConfigured('Error importing storage module %s: "%s"' % (module, e))
  224. try:
  225. return getattr(mod, classname)
  226. except AttributeError:
  227. raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
  228. class DefaultStorage(LazyObject):
  229. def _setup(self):
  230. self._wrapped = get_storage_class()()
  231. default_storage = DefaultStorage()