# Imports
from django.conf import settings
from myninjas.utils import File
import os
from PIL import Image
from unidecode import unidecode
from .constants import ALLOWED_CHARACTERS
# Exports
__all__ = (
"generate_thumbnail",
"get_unique_file_name",
"get_upload_to",
"remove_non_ascii",
"sanitize",
)
# Constants
UPLOAD_DIR = getattr(settings, "SUPERDJANGO_UPLOAD_DIR", "uploads")
# Functions
[docs]def generate_thumbnail(path, height=200, prefix=None, suffix="thumbnail", width=200):
"""Generate a thumbnail for the given image file.
:param path: The path to the image file.
:type path: str
:param height: The height of the thumbnail image.
:type height: int
:param prefix: The prefix of the new thumbnail file. The width and height will be added to the prefix in the form of
``prefix-WxH-file.extension``.
:type prefix: str
:param suffix: The suffix of the new thumbnail file. The width and height will be added to the suffix in the form of
``file-suffix-WxH.extension``.
:type suffix: str
:param width: The width of the thumbnail image.
:type width: int
:rtype: str
:returns: The path of the thumbnail file relative to ``MEDIA_ROOT``.
.. note::
Either the prefix or suffix is used in the new file name, but not both.
"""
file = File(path)
a = list()
if prefix is not None:
a.append(prefix)
a.append("%sx%s" % (width, height))
a.append("%s%s" % (file.name, file.extension))
else:
a.append(file.name)
a.append(suffix)
a.append("%sx%s%s" % (width, height, file.extension))
new_file_name = "-".join(a)
new_path = os.path.join(file.directory, new_file_name)
image = Image.open(path)
image.thumbnail((width, height))
image.save(new_path)
partial = new_path.replace(settings.MEDIA_ROOT, "")
if partial.startswith("/"):
partial = partial[1:]
return partial
[docs]def get_unique_file_name(file_name):
"""Given a file name to be uploaded, get a unique name if the file already exists.
:param file_name: The name of the file to be checked.
:type file_name: str
:rtype: str
"""
# First, clean up the name.
file_name = sanitize(file_name)
# The name is unique if the file doesn't already exist.
path = os.path.join(settings.MEDIA_ROOT, UPLOAD_DIR, file_name)
if not os.path.exists(path):
return file_name
# Now find a unique name.
suffix = 1
while True:
file_name = "%s-%s" % (suffix, file_name)
path = os.path.join(settings.MEDIA_ROOT, UPLOAD_DIR, file_name)
if not os.path.exists(path):
return file_name
[docs]def get_upload_to(instance, filename):
"""Get the path to upload a content file.
:param instance: The model instance.
:param filename: The name of the file.
:type filename: str
:rtype: str
.. important::
The model instance must implement a ``get_upload_to()`` method.
This allows the actual work of acquiring the upload path to be performed on the model where the file is defined.
.. code-block:: python
from superdjango.storage import import get_upload_to, remove_non_ascii
class Document(models.Model):
file = models.FileField(
_("file"),
help_text=_("Select the file to upload."),
upload_to=get_upload_to
)
def get_upload_to(self, filename):
file_name = self.file.field.storage.get_valid_name(filename)
file_name = remove_non_ascii(file_name)
directory_name = "documents"
path = os.path.join(directory_name, file_name)
return path
"""
return instance.get_upload_to(filename)
[docs]def remove_non_ascii(text):
"""Replace non-ASCII characters with ASCII characters.
:param text: The string that should have non-ASCII characters removed.
:type text: str
:rtype: str
"""
return unidecode(str(text))
[docs]def sanitize(file_name):
"""Make sure a given file name has no spaces or special characters.
:param file_name: The file name to be sanitized. Do NOT include the path.
:type file_name: str
:rtype: str
"""
file_name = remove_non_ascii(file_name)
file_name = file_name.replace(" ", "-")
a = list()
for c in file_name:
if c not in ALLOWED_CHARACTERS:
continue
a.append(c)
return ''.join(a)