Newer
Older
import mimetypes
from os.path import splitext
from django.core import validators
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from django.core.exceptions import ValidationError
from django.core.files.images import get_image_dimensions
from django.template.defaultfilters import filesizeformat
from django.utils.deconstruct import deconstructible
from django.utils.translation import ugettext_lazy as _
@deconstructible
class ImageDimensionsValidator:
"""
ImageField dimensions validator.
from https://gist.github.com/emilio-rst/4f81ea2718736a6aaf9bdb64d5f2ea6c
"""
def __init__(
self,
width=None,
height=None,
min_width=None,
max_width=None,
min_height=None,
max_height=None,
):
"""
Constructor
Args:
width (int): exact width
height (int): exact height
min_width (int): minimum width
min_height (int): minimum height
max_width (int): maximum width
max_height (int): maximum height
"""
self.width = width
self.height = height
self.min_width = min_width
self.max_width = max_width
self.min_height = min_height
self.max_height = max_height
def __call__(self, image):
w, h = get_image_dimensions(image)
if self.width is not None and w != self.width:
raise ValidationError(_("Width must be %dpx.") % (self.width,))
if self.height is not None and h != self.height:
raise ValidationError(_("Height must be %dpx.") % (self.height,))
if self.min_width is not None and w < self.min_width:
raise ValidationError(_("Minimum width must be %dpx.") % (self.min_width,))
if self.min_height is not None and h < self.min_height:
raise ValidationError(
_("Minimum height must be %dpx.") % (self.min_height,)
)
if self.max_width is not None and w > self.max_width:
raise ValidationError(_("Maximum width must be %dpx.") % (self.max_width,))
if self.max_height is not None and h > self.max_height:
raise ValidationError(
_("Maximum height must be %dpx.") % (self.max_height,)
)
@deconstructible
class FileValidator(object):
"""
Taken from https://gist.github.com/jrosebr1/2140738
Validator for files, checking the size, extension and mimetype.
Initialization parameters:
allowed_extensions: iterable with allowed file extensions
ie. ('txt', 'doc')
allowd_mimetypes: iterable with allowed mimetypes
ie. ('image/png', )
min_size: minimum number of bytes allowed
ie. 100
max_size: maximum number of bytes allowed
ie. 24*1024*1024 for 24 MB
Usage example::
MyModel(models.Model):
myfile = FileField(validators=FileValidator(max_size=24*1024*1024), ...)
"""
extension_message = _(
"Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'"
)
mime_message = _(
"MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s."
)
min_size_message = _(
"The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s."
)
max_size_message = _(
"The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s."
)
def __init__(self, *args, **kwargs):
self.allowed_extensions = kwargs.pop("allowed_extensions", None)
self.allowed_mimetypes = kwargs.pop("allowed_mimetypes", None)
self.min_size = kwargs.pop("min_size", 0)
self.max_size = kwargs.pop("max_size", None)
def __call__(self, value):
"""
Check the extension, content type and file size.
"""
# Check the extension
ext = splitext(value.name)[1][1:].lower()
if self.allowed_extensions and ext not in self.allowed_extensions:
message = self.extension_message % {
"extension": ext,
"allowed_extensions": ", ".join(self.allowed_extensions),
}
raise ValidationError(message)
# Check the content type
mimetype = mimetypes.guess_type(value.name)[0]
if self.allowed_mimetypes and mimetype not in self.allowed_mimetypes:
message = self.mime_message % {
"mimetype": mimetype,
"allowed_mimetypes": ", ".join(self.allowed_mimetypes),
}
raise ValidationError(message)
# Check the file size
filesize = len(value)
if self.max_size and filesize > self.max_size:
message = self.max_size_message % {
"size": filesizeformat(filesize),
"allowed_size": filesizeformat(self.max_size),
}
raise ValidationError(message)
elif filesize < self.min_size:
message = self.min_size_message % {
"size": filesizeformat(filesize),
"allowed_size": filesizeformat(self.min_size),
}
raise ValidationError(message)
class DomainValidator(validators.URLValidator):
message = "Enter a valid domain name."
def __call__(self, value):
"""
This is a bit hackish but since we don't have any built-in domain validator,
we use the url one, and prepend http:// in front of it.
If it fails, we know the domain is not valid.
"""
super().__call__("http://{}".format(value))
return value