123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import os
- import itertools
- import urlparse
- from mongoengine import *
- from django.conf import settings
- from django.core.files.storage import Storage
- from django.core.exceptions import ImproperlyConfigured
- class FileDocument(Document):
- """A document used to store a single file in GridFS.
- """
- file = FileField()
- class GridFSStorage(Storage):
- """A custom storage backend to store files in GridFS
- """
- def __init__(self, base_url=None):
- if base_url is None:
- base_url = settings.MEDIA_URL
- self.base_url = base_url
- self.document = FileDocument
- self.field = 'file'
- def delete(self, name):
- """Deletes the specified file from the storage system.
- """
- if self.exists(name):
- doc = self.document.objects.first()
- field = getattr(doc, self.field)
- self._get_doc_with_name(name).delete() # Delete the FileField
- field.delete() # Delete the FileDocument
- def exists(self, name):
- """Returns True if a file referened by the given name already exists in the
- storage system, or False if the name is available for a new file.
- """
- doc = self._get_doc_with_name(name)
- if doc:
- field = getattr(doc, self.field)
- return bool(field.name)
- else:
- return False
- def listdir(self, path=None):
- """Lists the contents of the specified path, returning a 2-tuple of lists;
- the first item being directories, the second item being files.
- """
- def name(doc):
- return getattr(doc, self.field).name
- docs = self.document.objects
- return [], [name(d) for d in docs if name(d)]
- def size(self, name):
- """Returns the total size, in bytes, of the file specified by name.
- """
- doc = self._get_doc_with_name(name)
- if doc:
- return getattr(doc, self.field).length
- else:
- raise ValueError("No such file or directory: '%s'" % name)
- def url(self, name):
- """Returns an absolute URL where the file's contents can be accessed
- directly by a web browser.
- """
- if self.base_url is None:
- raise ValueError("This file is not accessible via a URL.")
- return urlparse.urljoin(self.base_url, name).replace('\\', '/')
- def _get_doc_with_name(self, name):
- """Find the documents in the store with the given name
- """
- docs = self.document.objects
- doc = [d for d in docs if hasattr(getattr(d, self.field), 'name') and getattr(d, self.field).name == name]
- if doc:
- return doc[0]
- else:
- return None
- def _open(self, name, mode='rb'):
- doc = self._get_doc_with_name(name)
- if doc:
- return getattr(doc, self.field)
- else:
- raise ValueError("No file found with the name '%s'." % name)
- def get_available_name(self, name):
- """Returns a filename that's free on the target storage system, and
- available for new content to be written to.
- """
- file_root, file_ext = os.path.splitext(name)
- # If the filename already exists, add an underscore and a number (before
- # the file extension, if one exists) to the filename until the generated
- # filename doesn't exist.
- count = itertools.count(1)
- while self.exists(name):
- # file_ext includes the dot.
- name = os.path.join("%s_%s%s" % (file_root, count.next(), file_ext))
- return name
- def _save(self, name, content):
- doc = self.document()
- getattr(doc, self.field).put(content, filename=name)
- doc.save()
- return name
|