Skip to content

Commit 6975408

Browse files
author
Jesús Espino
committed
Reestructuring the code and new backward incompatible version
1 parent 1b42158 commit 6975408

File tree

6 files changed

+103
-104
lines changed

6 files changed

+103
-104
lines changed

setup.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
import os # To avoid an error importing validatedfile for versiontools
5-
os.environ['DJANGO_SETTINGS_MODULE'] = 'testing.settings'
6-
74
from setuptools import setup, find_packages
8-
import validatedfile
95

106
setup(
117
name = 'django-validated-file',

testing/forms.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
from django import forms
2-
from models import TestModel, TestModelNoValidate, TestContainer, TestElement
3-
from validatedfile import QuotaValidator
2+
from models import TestModel, TestModelNoValidate, TestElement
3+
from validatedfile.fields import QuotaValidator
4+
45

56
class TestModelForm(forms.ModelForm):
6-
7+
78
class Meta:
89
model = TestModel
910

1011

1112
class TestModelNoValidateForm(forms.ModelForm):
12-
13+
1314
class Meta:
1415
model = TestModelNoValidate
1516

1617

1718
class TestElementForm(forms.ModelForm):
1819

19-
the_file = forms.FileField(required = False,
20-
validators = [QuotaValidator(max_usage = 10000)])
20+
the_file = forms.FileField(required=False,
21+
validators=[QuotaValidator(max_usage=10000)])
2122

2223
class Meta:
2324
model = TestElement
@@ -27,15 +28,14 @@ def __init__(self, container, *args, **kwargs):
2728
super(TestElementForm, self).__init__(*args, **kwargs)
2829
self.container = container
2930
self.fields['the_file'].validators[0].update_quota(
30-
items = self.container.test_elements.all(),
31-
attr_name = 'the_file',
32-
)
31+
items=self.container.test_elements.all(),
32+
attr_name='the_file',
33+
)
3334

3435
def exceeds_quota(self):
3536
return self.fields['the_file'].validators[0].quota.exceeds()
3637

3738
def save(self, *args, **kwargs):
38-
element = super(TestElementForm, self).save(commit = False)
39+
element = super(TestElementForm, self).save(commit=False)
3940
element.container = self.container
4041
element.save()
41-

testing/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.db import models
2-
from validatedfile import ValidatedFileField
2+
from validatedfile.fields import ValidatedFileField
33

44
class TestModel(models.Model):
55
the_file = ValidatedFileField(

testing/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import os.path
77

8-
from validatedfile import FileQuota
8+
from validatedfile.fields import FileQuota
99

1010
from testing.models import TestModel, TestModelNoValidate, TestContainer, TestElement
1111
from testing.forms import TestModelForm, TestModelNoValidateForm, TestElementForm

validatedfile/__init__.py

Lines changed: 1 addition & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1 @@
1-
__version__ = (1, 0, 0, "final", 0)
2-
3-
from django.db import models
4-
from django import forms
5-
from django.template.defaultfilters import filesizeformat
6-
from django.utils.translation import ugettext as _
7-
8-
import magic
9-
10-
11-
class ValidatedFileField(models.FileField):
12-
def __init__(self, *args, **kwargs):
13-
self.content_types = kwargs.pop("content_types", [])
14-
self.max_upload_size = kwargs.pop("max_upload_size", 0)
15-
self.mime_lookup_length = kwargs.pop("mime_lookup_length", 4096)
16-
super(ValidatedFileField, self).__init__(*args, **kwargs)
17-
18-
def clean(self, *args, **kwargs):
19-
data = super(ValidatedFileField, self).clean(*args, **kwargs)
20-
file = data.file
21-
22-
if self.content_types:
23-
uploaded_content_type = getattr(file, 'content_type', '')
24-
25-
mg = magic.Magic(mime=True)
26-
content_type_magic = mg.from_buffer(
27-
file.read(self.mime_lookup_length)
28-
)
29-
file.seek(0)
30-
31-
# Prefere mime-type instead mime-type from http header
32-
if uploaded_content_type != content_type_magic:
33-
uploaded_content_type = content_type_magic
34-
35-
if not uploaded_content_type in self.content_types:
36-
raise forms.ValidationError(_('Files of type %(type)s are not supported.') % {'type': content_type_magic})
37-
38-
if self.max_upload_size and hasattr(file, '_size'):
39-
if file._size > self.max_upload_size:
40-
raise forms.ValidationError(_('Files of size greater than %(max_size)s are not allowed. Your file is %(current_size)s') %
41-
{'max_size': filesizeformat(self.max_upload_size),
42-
'current_size': filesizeformat(file._size)})
43-
44-
return data
45-
46-
47-
class FileQuota(object):
48-
49-
def __init__(self, max_usage = -1):
50-
self.current_usage = 0
51-
self.max_usage = max_usage
52-
53-
def update(self, items, attr_name):
54-
self.current_usage = 0
55-
for item in items:
56-
the_file = getattr(item, attr_name, None)
57-
if the_file:
58-
try:
59-
self.current_usage += the_file.size
60-
except AttributeError:
61-
pass # Protect against the inconsistence of that the file has been deleted in storage but still is in the field
62-
63-
def exceeds(self, size = 0):
64-
if self.max_usage >= 0:
65-
return (self.current_usage + size > self.max_usage)
66-
else:
67-
return False
68-
69-
def near_limit(self, limit_threshold = 0.8):
70-
return (float(self.current_usage) / float(self.max_usage)) > limit_threshold
71-
72-
73-
class QuotaValidator(object):
74-
75-
def __init__(self, max_usage):
76-
self.quota = FileQuota(max_usage)
77-
78-
def update_quota(self, items, attr_name):
79-
self.quota.update(items, attr_name)
80-
81-
def __call__(self, file):
82-
file_size = file.size
83-
if self.quota.exceeds(file_size):
84-
raise forms.ValidationError(_('Please keep the total uploaded files under %(total_size)s. With this file, the total would be %(exceed_size)s.' %
85-
{'total_size': filesizeformat(self.quota.max_usage),
86-
'exceed_size': filesizeformat(self.quota.current_usage + file_size)}))
87-
1+
__version__ = (2, 0, 0, "final", 0)

validatedfile/fields.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from django.db import models
2+
from django import forms
3+
from django.template.defaultfilters import filesizeformat
4+
from django.utils.translation import ugettext as _
5+
6+
import magic
7+
8+
9+
class ValidatedFileField(models.FileField):
10+
def __init__(self, *args, **kwargs):
11+
self.content_types = kwargs.pop("content_types", [])
12+
self.max_upload_size = kwargs.pop("max_upload_size", 0)
13+
self.mime_lookup_length = kwargs.pop("mime_lookup_length", 4096)
14+
super(ValidatedFileField, self).__init__(*args, **kwargs)
15+
16+
def clean(self, *args, **kwargs):
17+
data = super(ValidatedFileField, self).clean(*args, **kwargs)
18+
file = data.file
19+
20+
if self.content_types:
21+
uploaded_content_type = getattr(file, 'content_type', '')
22+
23+
mg = magic.Magic(mime=True)
24+
content_type_magic = mg.from_buffer(
25+
file.read(self.mime_lookup_length)
26+
)
27+
file.seek(0)
28+
29+
# Prefere mime-type instead mime-type from http header
30+
if uploaded_content_type != content_type_magic:
31+
uploaded_content_type = content_type_magic
32+
33+
if not uploaded_content_type in self.content_types:
34+
raise forms.ValidationError(
35+
_('Files of type %(type)s are not supported.') % {'type': content_type_magic}
36+
)
37+
38+
if self.max_upload_size and hasattr(file, '_size'):
39+
if file._size > self.max_upload_size:
40+
raise forms.ValidationError(
41+
_('Files of size greater than %(max_size)s are not allowed. Your file is %(current_size)s') %
42+
{'max_size': filesizeformat(self.max_upload_size), 'current_size': filesizeformat(file._size)}
43+
)
44+
45+
return data
46+
47+
48+
class FileQuota(object):
49+
50+
def __init__(self, max_usage=-1):
51+
self.current_usage = 0
52+
self.max_usage = max_usage
53+
54+
def update(self, items, attr_name):
55+
self.current_usage = 0
56+
for item in items:
57+
the_file = getattr(item, attr_name, None)
58+
if the_file:
59+
try:
60+
self.current_usage += the_file.size
61+
except AttributeError:
62+
pass # Protect against the inconsistence of that the file
63+
# has been deleted in storage but still is in the field
64+
65+
def exceeds(self, size=0):
66+
if self.max_usage >= 0:
67+
return (self.current_usage + size > self.max_usage)
68+
else:
69+
return False
70+
71+
def near_limit(self, limit_threshold=0.8):
72+
return (float(self.current_usage) / float(self.max_usage)) > limit_threshold
73+
74+
75+
class QuotaValidator(object):
76+
77+
def __init__(self, max_usage):
78+
self.quota = FileQuota(max_usage)
79+
80+
def update_quota(self, items, attr_name):
81+
self.quota.update(items, attr_name)
82+
83+
def __call__(self, file):
84+
file_size = file.size
85+
if self.quota.exceeds(file_size):
86+
raise forms.ValidationError(
87+
_('Please keep the total uploaded files under %(total_size)s. With this file, the total would be %(exceed_size)s.' %
88+
{'total_size': filesizeformat(self.quota.max_usage), 'exceed_size': filesizeformat(self.quota.current_usage + file_size)})
89+
)

0 commit comments

Comments
 (0)