Update (Jan 23, 2017)
To avoid this, you can simply pass preload_metadata=False
when creating a Storage
, or set AWS_PRELOAD_METADATA = False
in settings.
Thanks @r3mot for this suggestion in the comments.
Original Answer
In fact, it's because S3BotoStorage.exists
makes a call to S3BotoStorage.entries
, which is as follows:
@property
def entries(self):
"""
Get the locally cached files for the bucket.
"""
if self.preload_metadata and not self._entries:
self._entries = dict((self._decode_name(entry.key), entry)
for entry in self.bucket.list(prefix=self.location))
The best way to handle this situation would be to subclass S3BotoStorage
as follows:
from storages.backends.s3boto import S3BotoStorage, parse_ts_extended
class MyS3BotoStorage(S3BotoStorage):
def exists(self, name):
name = self._normalize_name(self._clean_name(name))
k = self.bucket.new_key(self._encode_name(name))
return k.exists()
def size(self, name):
name = self._normalize_name(self._clean_name(name))
return self.bucket.get_key(self._encode_name(name)).size
def modified_time(self, name):
name = self._normalize_name(self._clean_name(name))
k = self.bucket.get_key(self._encode_name(name))
return parse_ts_extended(k.last_modified)
You'll have to just put this subclass in one of your app's modules, and reference it via dotted path in your settings module. The only drawback to this subclass is that each call to any of the 3 overridden methods will result in a web request, which might not be a big deal.