Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Imports
3from django.conf import settings
4from myninjas.utils import File
5import os
6from PIL import Image
7from unidecode import unidecode
8from .constants import ALLOWED_CHARACTERS
10# Exports
12__all__ = (
13 "generate_thumbnail",
14 "get_unique_file_name",
15 "get_upload_to",
16 "remove_non_ascii",
17 "sanitize",
18)
20# Constants
22UPLOAD_DIR = getattr(settings, "SUPERDJANGO_UPLOAD_DIR", "uploads")
24# Functions
27def generate_thumbnail(path, height=200, prefix=None, suffix="thumbnail", width=200):
28 """Generate a thumbnail for the given image file.
30 :param path: The path to the image file.
31 :type path: str
33 :param height: The height of the thumbnail image.
34 :type height: int
36 :param prefix: The prefix of the new thumbnail file. The width and height will be added to the prefix in the form of
37 ``prefix-WxH-file.extension``.
38 :type prefix: str
40 :param suffix: The suffix of the new thumbnail file. The width and height will be added to the suffix in the form of
41 ``file-suffix-WxH.extension``.
42 :type suffix: str
44 :param width: The width of the thumbnail image.
45 :type width: int
47 :rtype: str
48 :returns: The path of the thumbnail file relative to ``MEDIA_ROOT``.
50 .. note::
51 Either the prefix or suffix is used in the new file name, but not both.
53 """
54 file = File(path)
56 a = list()
57 if prefix is not None:
58 a.append(prefix)
59 a.append("%sx%s" % (width, height))
60 a.append("%s%s" % (file.name, file.extension))
61 else:
62 a.append(file.name)
63 a.append(suffix)
64 a.append("%sx%s%s" % (width, height, file.extension))
66 new_file_name = "-".join(a)
67 new_path = os.path.join(file.directory, new_file_name)
69 image = Image.open(path)
70 image.thumbnail((width, height))
71 image.save(new_path)
73 partial = new_path.replace(settings.MEDIA_ROOT, "")
74 if partial.startswith("/"):
75 partial = partial[1:]
77 return partial
80def get_unique_file_name(file_name):
81 """Given a file name to be uploaded, get a unique name if the file already exists.
83 :param file_name: The name of the file to be checked.
84 :type file_name: str
86 :rtype: str
88 """
89 # First, clean up the name.
90 file_name = sanitize(file_name)
92 # The name is unique if the file doesn't already exist.
93 path = os.path.join(settings.MEDIA_ROOT, UPLOAD_DIR, file_name)
94 if not os.path.exists(path):
95 return file_name
97 # Now find a unique name.
98 suffix = 1
99 while True:
100 file_name = "%s-%s" % (suffix, file_name)
101 path = os.path.join(settings.MEDIA_ROOT, UPLOAD_DIR, file_name)
102 if not os.path.exists(path):
103 return file_name
106def get_upload_to(instance, filename):
107 """Get the path to upload a content file.
109 :param instance: The model instance.
111 :param filename: The name of the file.
112 :type filename: str
114 :rtype: str
116 .. important::
117 The model instance must implement a ``get_upload_to()`` method.
119 This allows the actual work of acquiring the upload path to be performed on the model where the file is defined.
121 .. code-block:: python
123 from superdjango.storage import import get_upload_to, remove_non_ascii
125 class Document(models.Model):
127 file = models.FileField(
128 _("file"),
129 help_text=_("Select the file to upload."),
130 upload_to=get_upload_to
131 )
133 def get_upload_to(self, filename):
134 file_name = self.file.field.storage.get_valid_name(filename)
135 file_name = remove_non_ascii(file_name)
137 directory_name = "documents"
138 path = os.path.join(directory_name, file_name)
140 return path
142 """
143 return instance.get_upload_to(filename)
146def remove_non_ascii(text):
147 """Replace non-ASCII characters with ASCII characters.
149 :param text: The string that should have non-ASCII characters removed.
150 :type text: str
152 :rtype: str
154 """
155 return unidecode(str(text))
158def sanitize(file_name):
159 """Make sure a given file name has no spaces or special characters.
161 :param file_name: The file name to be sanitized. Do NOT include the path.
162 :type file_name: str
164 :rtype: str
166 """
167 file_name = remove_non_ascii(file_name)
169 file_name = file_name.replace(" ", "-")
171 a = list()
172 for c in file_name:
173 if c not in ALLOWED_CHARACTERS:
174 continue
176 a.append(c)
178 return ''.join(a)