You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

103 lines
2.5 KiB

"""
Redis storages backend to help store binary data.
"""
import base64
import io
import redis
import uuid
import re
from shutil import copyfileobj
from tempfile import SpooledTemporaryFile
from django.conf import settings
from django.core.files.base import File
from django.core.files.storage import Storage
from django.utils.deconstruct import deconstructible
EX_EXPIRY = 60*60*24*30 # 1 month expiry in seconds
def generate_unique_filename(instance, filename):
return '{}_{}'.format(uuid.uuid4(), re.sub('[^0-9a-zA-Z]+', '_', filename))
class RedisFile(File):
def __init__(self, name, storage):
self.name = name
self._storage = storage
self._file = None
def _get_file(self):
if self._file is None:
self._file = SpooledTemporaryFile()
# get from redis
content = self._storage.client.get(self.name)
# stored as base64 .. decode
content = base64.b64decode(content)
with io.BytesIO(content) as file_content:
copyfileobj(file_content, self._file)
self._file.seek(0)
return self._file
def _set_file(self, value):
self._file = value
file = property(_get_file, _set_file)
@deconstructible
class RedisStorage(Storage):
def __init__(self):
self.client = redis.Redis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
db=settings.REDIS_DB,
password=settings.REDIS_PASSWORD
)
def _full_key_name(self, name):
return name
def delete(self, name):
self.client.delete(self._full_key_name(name))
def exists(self, name):
return self.client.exists(self._full_key_name(name))
def listdir(self, path):
return '', ''
def size(self, name):
return ''
def url(self, name):
return ''
def _open(self, name, mode='rb'):
remote_file = RedisFile(self._full_key_name(name), self)
return remote_file
def _save(self, name, content):
content.open()
data = base64.b64encode(content.read())
self.client.set(self._full_key_name(name), data, ex=EX_EXPIRY)
content.close()
return name
def get_available_name(self, name, max_length=None):
"""
Allow storage backend to generate a new name if there is already an existing file. Not used for this Redis
implementation.
"""
name = self._full_key_name(name)
return super().get_available_name(name, max_length)