Ticket #13960: filetransfers.4.diff
File filetransfers.4.diff, 30.9 KB (added by , 14 years ago) |
---|
-
django/conf/global_settings.py
diff -r c8038a5c808d django/conf/global_settings.py
a b 258 258 # Default file storage mechanism that holds media. 259 259 DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' 260 260 261 # High-level transfer backends 262 FILE_TRANSFER_BACKENDS = ( 263 'django.core.files.transfers.DefaultFileBackend', 264 ) 265 266 # The default transfer backend's configuration mapping transfer_id to 267 # backend name 268 DEFAULT_FILE_TRANSFER_BACKENDS = {} 269 261 270 # Absolute path to the directory that holds media. 262 271 # Example: "/home/media/media.lawrence.com/" 263 272 MEDIA_ROOT = '' -
django/contrib/admin/options.py
diff -r c8038a5c808d django/contrib/admin/options.py
a b 9 9 from django.contrib import messages 10 10 from django.views.decorators.csrf import csrf_protect 11 11 from django.core.exceptions import PermissionDenied, ValidationError 12 from django.core.files.transfers import prepare_upload 12 13 from django.db import models, transaction 13 14 from django.db.models.fields import BLANK_CHOICE_DASH 14 15 from django.http import Http404, HttpResponse, HttpResponseRedirect … … 602 603 """ 603 604 formset.save() 604 605 605 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): 606 def has_file_field(self, form, formsets): 607 for field in form.fields.values(): 608 if isinstance(field, forms.FileField): 609 return True 610 for formset in formsets: 611 for form in formset.forms: 612 for field in form.fields.values(): 613 if isinstance(field, forms.FileField): 614 return True 615 return False 616 617 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None, has_file_field=True): 606 618 opts = self.model._meta 607 619 app_label = opts.app_label 608 620 ordered_objects = opts.get_ordered_objects() 621 622 if has_file_field: 623 if not form_url: 624 form_url = request.get_full_path() 625 transfer_id = '%s.%s' % (self.__class__.__module__, 626 self.__class__.__name__) 627 if add: 628 transfer_id += '.add' 629 if change: 630 transfer_id += '.change' 631 form_url, upload_data = prepare_upload(transfer_id, request, url=form_url) 632 context.update({ 633 'file_upload_data': mark_safe(''.join('<input type="hidden" name="%s" value="%s" />' 634 % (escape(name), escape(value)) 635 for name, value in upload_data.items())), 636 }) 637 609 638 context.update({ 610 639 'add': add, 611 640 'change': change, 612 641 'has_add_permission': self.has_add_permission(request), 613 642 'has_change_permission': self.has_change_permission(request, obj), 614 643 'has_delete_permission': self.has_delete_permission(request, obj), 615 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField,644 'has_file_field': has_file_field, 616 645 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 617 646 'ordered_objects': ordered_objects, 618 647 'form_url': mark_safe(form_url), … … 822 851 queryset=inline.queryset(request)) 823 852 formsets.append(formset) 824 853 854 has_file_field = self.has_file_field(form, formsets) 855 825 856 adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), 826 857 self.prepopulated_fields, self.get_readonly_fields(request), 827 858 model_admin=self) … … 848 879 'app_label': opts.app_label, 849 880 } 850 881 context.update(extra_context or {}) 851 return self.render_change_form(request, context, form_url=form_url, add=True )882 return self.render_change_form(request, context, form_url=form_url, add=True, has_file_field=has_file_field) 852 883 853 884 @csrf_protect_m 854 885 @transaction.commit_on_success … … 913 944 queryset=inline.queryset(request)) 914 945 formsets.append(formset) 915 946 947 has_file_field = self.has_file_field(form, formsets) 948 916 949 adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), 917 950 self.prepopulated_fields, self.get_readonly_fields(request, obj), 918 951 model_admin=self) … … 940 973 'app_label': opts.app_label, 941 974 } 942 975 context.update(extra_context or {}) 943 return self.render_change_form(request, context, change=True, obj=obj )976 return self.render_change_form(request, context, change=True, obj=obj, has_file_field=has_file_field) 944 977 945 978 @csrf_protect_m 946 979 def changelist_view(self, request, extra_context=None): -
django/contrib/admin/templates/admin/change_form.html
diff -r c8038a5c808d django/contrib/admin/templates/admin/change_form.html
a b 41 41 {{ adminform.form.non_field_errors }} 42 42 {% endif %} 43 43 44 {{ file_upload_data }} 45 44 46 {% for fieldset in adminform %} 45 47 {% include "admin/includes/fieldset.html" %} 46 48 {% endfor %} -
django/contrib/admin/widgets.py
diff -r c8038a5c808d django/contrib/admin/widgets.py
a b 94 94 95 95 def render(self, name, value, attrs=None): 96 96 output = [] 97 if value and hasattr(value, "url"):97 if value and hasattr(value, 'download_url'): 98 98 output.append('%s <a target="_blank" href="%s">%s</a> <br />%s ' % \ 99 (_('Currently:'), value. url, value, _('Change:')))99 (_('Currently:'), value.download_url(), value, _('Change:'))) 100 100 output.append(super(AdminFileWidget, self).render(name, value, attrs)) 101 101 return mark_safe(u''.join(output)) 102 102 -
new file django/core/files/transfers.py
diff -r c8038a5c808d django/core/files/transfers.py
- + 1 from django.conf import settings 2 from django.core.exceptions import ImproperlyConfigured 3 from django.core.files.storage import default_storage 4 from django.http import HttpResponse 5 from django.utils.encoding import smart_str 6 from django.utils.importlib import import_module 7 import mimetypes 8 import urlparse 9 10 class BaseFileBackend(object): 11 def __init__(self, transfer_id): 12 self.transfer_id = transfer_id 13 14 def prepare_upload(self, request, url): 15 return None 16 17 def serve(self, request, file, save_as=False, content_type=None): 18 return None 19 20 def download_url(self, file): 21 return None 22 23 def get_storage_backend(self): 24 return None 25 26 class DefaultFileBackend(BaseFileBackend): 27 def _get_backend_path(self): 28 if self.transfer_id in settings.DEFAULT_FILE_TRANSFER_BACKENDS: 29 return settings.DEFAULT_FILE_TRANSFER_BACKENDS[self.transfer_id] 30 parts = self.transfer_id.split('.')[:-1] 31 while parts: 32 name = '.'.join(parts) + '.*' 33 if name in settings.DEFAULT_FILE_TRANSFER_BACKENDS: 34 return settings.DEFAULT_FILE_TRANSFER_BACKENDS[name] 35 del parts[-1] 36 return None 37 38 def _get_backend(self): 39 path = self._get_backend_path() 40 if path: 41 return load_backend(path, self.transfer_id) 42 return None 43 44 def prepare_upload(self, *args, **kwargs): 45 backend = self._get_backend() 46 if backend: 47 return backend.prepare_upload(*args, **kwargs) 48 return None 49 50 def serve(self, *args, **kwargs): 51 backend = self._get_backend() 52 if backend: 53 return backend.serve(*args, **kwargs) 54 return None 55 56 def download_url(self, *args, **kwargs): 57 backend = self._get_backend() 58 if backend: 59 return backend.download_url(*args, **kwargs) 60 return None 61 62 def get_storage_backend(self, *args, **kwargs): 63 backend = self._get_backend() 64 if backend: 65 return backend.get_storage_backend(*args, **kwargs) 66 return None 67 68 # Public API 69 def prepare_upload(transfer_id, request, url=None): 70 if not url: 71 url = request.get_full_path() 72 for backend in _get_backends(transfer_id): 73 result = backend.prepare_upload(request, url) 74 if result is not None: 75 return result 76 77 # By default we simply return the URL unmodified 78 return url, {} 79 80 def serve_file(transfer_id, request, file, save_as=False, content_type=None): 81 filename = file.name.rsplit('/')[-1] 82 if save_as is True: 83 save_as = filename 84 if not content_type: 85 content_type = mimetypes.guess_type(filename)[0] 86 for backend in _get_backends(transfer_id): 87 result = backend.serve(request, file, save_as=save_as, content_type=content_type) 88 if result is not None: 89 return result 90 91 return _default_serve_file(file, save_as, content_type) 92 93 def download_url(transfer_id, file): 94 for backend in _get_backends(transfer_id): 95 result = backend.download_url(file) 96 if result is not None: 97 return result 98 99 # By default we use MEDIA_URL 100 return urlparse.urljoin(settings.MEDIA_URL, file.name).replace('\\', '/') 101 102 def get_storage_backend(transfer_id): 103 for backend in _get_backends(transfer_id): 104 result = backend.get_storage_backend() 105 if result is not None: 106 return result 107 108 # By default there is no public download URL 109 return default_storage 110 111 # Internal utilities 112 class ChunkedFile(object): 113 def __init__(self, file): 114 self.file = file 115 116 def __iter__(self): 117 return self.file.chunks() 118 119 def _default_serve_file(file, save_as, content_type): 120 """ 121 Serves the file in chunks for efficiency reasons. 122 123 The transfer still goes through Django itself, so it's much worse than 124 using the web server, but at least it works with all configurations. 125 """ 126 response = HttpResponse(ChunkedFile(file), content_type=content_type) 127 if save_as: 128 response['Content-Disposition'] = smart_str(u'attachment; filename=%s' % save_as) 129 if file.size is not None: 130 response['Content-Length'] = file.size 131 return response 132 133 def _get_backends(*args, **kwargs): 134 return (load_backend(name, *args, **kwargs) 135 for name in settings.FILE_TRANSFER_BACKENDS) 136 137 def load_backend(path, *args, **kwargs): 138 module_name, attr_name = path.rsplit('.', 1) 139 try: 140 mod = import_module(module_name) 141 except ImportError, e: 142 raise ImproperlyConfigured('Error importing file backend module %s: "%s"' % (module_name, e)) 143 except ValueError, e: 144 raise ImproperlyConfigured('Error importing file backend module. Is FILE_TRANSFER_BACKENDS a correctly defined list or tuple?') 145 try: 146 backend = getattr(mod, attr_name) 147 except AttributeError: 148 raise ImproperlyConfigured('Module "%s" does not define a "%s" file backend' % (module_name, attr_name)) 149 return backend(*args, **kwargs) -
django/core/files/uploadhandler.py
diff -r c8038a5c808d django/core/files/uploadhandler.py
a b 84 84 """ 85 85 pass 86 86 87 def new_file(self, field_name, file_name, content_type, content_length, charset=None):87 def new_file(self, field_name, file_name, content_type, content_length, charset=None, content_type_extra=None): 88 88 """ 89 89 Signal that a new file has been started. 90 90 … … 96 96 self.content_type = content_type 97 97 self.content_length = content_length 98 98 self.charset = charset 99 if content_type_extra is None: 100 content_type_extra = {} 101 self.content_type_extra = content_type_extra 99 102 100 103 def receive_data_chunk(self, raw_data, start): 101 104 """ -
django/db/models/fields/files.py
diff -r c8038a5c808d django/db/models/fields/files.py
a b 6 6 from django.conf import settings 7 7 from django.db.models.fields import Field 8 8 from django.core.files.base import File, ContentFile 9 from django.core.files.storage import default_storage10 9 from django.core.files.images import ImageFile, get_image_dimensions 10 from django.core.files.transfers import serve_file, download_url, get_storage_backend 11 11 from django.core.files.uploadedfile import UploadedFile 12 12 from django.utils.functional import curry 13 13 from django.db.models import signals … … 139 139 # be restored later, by FileDescriptor below. 140 140 return {'name': self.name, 'closed': False, '_committed': True, '_file': None} 141 141 142 def serve(self, request, save_as=False, content_type=None): 143 self._require_file() 144 return serve_file(self.field.transfer_id, request, self, save_as=save_as, content_type=content_type) 145 146 def download_url(self): 147 self._require_file() 148 return download_url(self.field.transfer_id, self) 149 142 150 class FileDescriptor(object): 143 151 """ 144 152 The descriptor for the file attribute on the model instance. Returns a … … 219 227 220 228 description = ugettext_lazy("File path") 221 229 222 def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):230 def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, transfer_id=None, **kwargs): 223 231 for arg in ('primary_key', 'unique'): 224 232 if arg in kwargs: 225 233 raise TypeError("'%s' is not a valid argument for %s." % (arg, self.__class__)) 226 234 227 self.storage = storage or default_storage 235 self.transfer_id = transfer_id 236 self.storage = storage 228 237 self.upload_to = upload_to 229 238 if callable(upload_to): 230 239 self.generate_filename = upload_to … … 257 266 258 267 def contribute_to_class(self, cls, name): 259 268 super(FileField, self).contribute_to_class(cls, name) 269 if self.transfer_id is None: 270 self.transfer_id = '%s.%s.%s' % (cls.__module__, 271 cls.__name__, 272 self.name) 273 if self.storage is None: 274 self.storage = get_storage_backend(self.transfer_id) 260 275 setattr(cls, self.name, self.descriptor_class(self)) 261 276 signals.post_delete.connect(self.delete_file, sender=cls) 262 277 -
django/forms/forms.py
diff -r c8038a5c808d django/forms/forms.py
a b 3 3 """ 4 4 5 5 from django.core.exceptions import ValidationError 6 from django.core.files.transfers import prepare_upload 6 7 from django.utils.copycompat import deepcopy 7 8 from django.utils.datastructures import SortedDict 8 9 from django.utils.html import conditional_escape … … 10 11 from django.utils.safestring import mark_safe 11 12 12 13 from fields import Field, FileField 13 from widgets import Media, media_property, TextInput, Textarea 14 from widgets import Media, media_property, TextInput, Textarea, HiddenInput 14 15 from util import flatatt, ErrorDict, ErrorList 15 16 16 __all__ = ('BaseForm', 'Form' )17 __all__ = ('BaseForm', 'Form', 'RequestForm') 17 18 18 19 NON_FIELD_ERRORS = '__all__' 19 20 … … 377 378 """ 378 379 return [field for field in self if not field.is_hidden] 379 380 381 class BaseRequestFormTraits(object): 382 def __init__(self, request, url=None, prepare_upload=True, transfer_id=None, **kwargs): 383 if request.method == 'POST': 384 kwargs.setdefault('data', request.POST) 385 kwargs.setdefault('files', request.FILES) 386 387 self.request = request 388 389 # _url is the original url 390 self._url = url or request.get_full_path() 391 if not transfer_id: 392 self.transfer_id = '%s.%s' % (self.__class__.__module__, 393 self.__class__.__name__) 394 self._file_upload_data = {} 395 super(BaseRequestFormTraits, self).__init__(**kwargs) 396 if prepare_upload: 397 self.prepare_upload() 398 399 def prepare_upload(self): 400 if self.files: 401 return 402 403 self._remove_upload_data() 404 405 # Only prepare upload if a FileField exists 406 if not self._has_file_field(): 407 return 408 409 result = prepare_upload(self.transfer_id, self.request, url=self._url) 410 self.url, self._file_upload_data = result 411 412 self._add_upload_data() 413 414 def _has_file_field(self): 415 for field in self.fields.values(): 416 if isinstance(field, FileField): 417 return True 418 return False 419 420 def _remove_upload_data(self): 421 for name in self._file_upload_data: 422 del self.fields[name] 423 424 def _add_upload_data(self): 425 for name, value in self._file_upload_data.items(): 426 self.fields[name] = Field(initial=value, required=False, widget=HiddenInput) 427 380 428 class Form(BaseForm): 381 429 "A collection of Fields, plus their associated data." 382 430 # This is a separate class from BaseForm in order to abstract the way … … 386 434 # BaseForm itself has no way of designating self.fields. 387 435 __metaclass__ = DeclarativeFieldsMetaclass 388 436 437 class RequestForm(BaseRequestFormTraits, BaseForm): 438 __metaclass__ = DeclarativeFieldsMetaclass 439 389 440 class BoundField(StrAndUnicode): 390 441 "A Field plus data" 391 442 def __init__(self, form, field, name): -
django/forms/formsets.py
diff -r c8038a5c808d django/forms/formsets.py
a b 1 from forms import Form 1 from forms import Form, BaseRequestFormTraits, RequestForm 2 2 from django.core.exceptions import ValidationError 3 3 from django.utils.encoding import StrAndUnicode 4 4 from django.utils.safestring import mark_safe 5 5 from django.utils.translation import ugettext as _ 6 from fields import IntegerField, BooleanField6 from fields import Field, IntegerField, BooleanField, FileField 7 7 from widgets import Media, HiddenInput 8 8 from util import ErrorList 9 9 10 __all__ = ('BaseFormSet', ' all_valid')10 __all__ = ('BaseFormSet', 'BaseRequestFormSet', 'all_valid') 11 11 12 12 # special field names 13 13 TOTAL_FORM_COUNT = 'TOTAL_FORMS' … … 326 326 forms = u' '.join([form.as_table() for form in self.forms]) 327 327 return mark_safe(u'\n'.join([unicode(self.management_form), forms])) 328 328 329 class BaseRequestFormSetTraits(BaseRequestFormTraits): 330 def _construct_form(self, *args, **kwargs): 331 if isinstance(self.form, BaseRequestFormTraits): 332 kwargs.update({ 333 'request': self.request, 334 'url': self._url, 335 'prepare_upload': False, 336 }) 337 super(BaseRequestFormSetTraits, self)._construct_form(*args, **kwargs) 338 339 def _get_empty_form(self, *args, **kwargs): 340 if isinstance(self.form, BaseRequestFormTraits): 341 kwargs.update({ 342 'request': self.request, 343 'url': self._url, 344 'prepare_upload': False, 345 }) 346 super(BaseRequestFormSetTraits, self)._get_empty_form(*args, **kwargs) 347 empty_form = property(_get_empty_form) 348 349 def _has_file_field(self): 350 for form in self.forms: 351 for field in form.fields.values(): 352 if isinstance(field, FileField): 353 return True 354 return False 355 356 def _remove_upload_data(self): 357 if hasattr(self, '_upload_data_form'): 358 self.forms.remove(self._upload_data_form) 359 360 def _add_upload_data(self): 361 form = RequestForm(self.request) 362 for name, value in self._file_upload_data.items(): 363 form.fields[name] = Field(initial=value, required=False, widget=HiddenInput) 364 self._upload_data_form = form 365 self.forms.append(form) 366 367 class BaseRequestFormSet(BaseRequestFormSetTraits, BaseFormSet): 368 pass 369 329 370 def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, 330 371 can_delete=False, max_num=None): 331 372 """Return a FormSet for the given form class.""" -
django/forms/models.py
diff -r c8038a5c808d django/forms/models.py
a b 12 12 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS 13 13 from django.core.validators import EMPTY_VALUES 14 14 from util import ErrorList 15 from forms import BaseForm, get_declared_fields15 from forms import BaseForm, BaseRequestFormTraits, get_declared_fields 16 16 from fields import Field, ChoiceField 17 17 from widgets import SelectMultiple, HiddenInput, MultipleHiddenInput 18 18 from widgets import media_property 19 from formsets import BaseFormSet, formset_factory, DELETION_FIELD_NAME 19 from formsets import BaseFormSet, formset_factory, DELETION_FIELD_NAME, BaseRequestFormSetTraits 20 20 21 21 __all__ = ( 22 22 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model', 23 23 'save_instance', 'form_for_fields', 'ModelChoiceField', 24 'ModelMultipleChoiceField', 24 'ModelMultipleChoiceField', 'RequestModelForm', 'BaseRequestModelFormSet', 25 'BaseInlineRequestFormSet', 25 26 ) 26 27 27 28 def construct_instance(form, instance, fields=None, exclude=None): … … 201 202 formfield_callback = attrs.pop('formfield_callback', 202 203 lambda f, **kwargs: f.formfield(**kwargs)) 203 204 try: 204 parents = [b for b in bases if issubclass(b, ModelForm)]205 parents = [b for b in bases if issubclass(b, (BaseModelForm))] 205 206 except NameError: 206 207 # We are defining ModelForm itself. 207 208 parents = None … … 375 376 class ModelForm(BaseModelForm): 376 377 __metaclass__ = ModelFormMetaclass 377 378 379 class RequestModelForm(BaseRequestFormTraits, BaseModelForm): 380 __metaclass__ = ModelFormMetaclass 381 378 382 def modelform_factory(model, form=ModelForm, fields=None, exclude=None, 379 383 formfield_callback=lambda f: f.formfield()): 380 384 # Create the inner Meta class. FIXME: ideally, we should be able to … … 658 662 form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput) 659 663 super(BaseModelFormSet, self).add_fields(form, index) 660 664 665 class BaseRequestModelFormSet(BaseRequestFormSetTraits, BaseModelFormSet): 666 pass 667 661 668 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(), 662 669 formset=BaseModelFormSet, 663 670 extra=1, can_delete=False, can_order=False, … … 768 775 unique_check = [field for field in unique_check if field != self.fk.name] 769 776 return super(BaseInlineFormSet, self).get_unique_error_message(unique_check) 770 777 778 class BaseInlineRequestFormSet(BaseRequestFormSetTraits, BaseInlineFormSet): 779 pass 771 780 772 781 def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False): 773 782 """ -
django/http/multipartparser.py
diff -r c8038a5c808d django/http/multipartparser.py
a b 169 169 file_name = self.IE_sanitize(unescape_entities(file_name)) 170 170 171 171 content_type = meta_data.get('content-type', ('',))[0].strip() 172 content_type_extra = meta_data.get('content-type', (0,{}))[1] 172 173 try: 173 charset = meta_data.get('content-type', (0,{}))[1].get('charset', None)174 charset = content_type_extra.get('charset', None) 174 175 except: 175 176 charset = None 176 177 … … 185 186 try: 186 187 handler.new_file(field_name, file_name, 187 188 content_type, content_length, 188 charset )189 charset, content_type_extra) 189 190 except StopFutureHandlers: 190 191 break 191 192 -
new file tests/regressiontests/file_uploads/backends.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/backends.py
- + 1 from django.conf import settings 2 from django.core.files.transfers import BaseFileBackend 3 from django.http import HttpResponseRedirect 4 import models 5 6 class TestFileBackend(BaseFileBackend): 7 def prepare_upload(self, request, url, *args, **kwargs): 8 return '/redirect' + url, {'x-extra': 'abcd', 'x-data': 'efg'} 9 10 def serve(self, request, file, *args, **kwargs): 11 if not file.name.endswith('pass'): 12 return HttpResponseRedirect('/download/') 13 14 def download_url(self, file): 15 if not file.name.endswith('pass'): 16 return '/public/' 17 18 def get_storage_backend(self, *args, **kwargs): 19 return models.temp_storage -
new file tests/regressiontests/file_uploads/forms.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/forms.py
- + 1 from django import forms 2 from models import FileModel 3 4 class FileForm(forms.RequestModelForm): 5 class Meta: 6 model = FileModel -
tests/regressiontests/file_uploads/models.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/models.py
a b 1 1 import tempfile 2 2 import os 3 from django.conf import settings 3 4 from django.db import models 4 5 from django.core.files.storage import FileSystemStorage 5 6 6 7 temp_storage = FileSystemStorage(tempfile.mkdtemp()) 7 8 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 9 settings.DEFAULT_FILE_TRANSFER_BACKENDS.update({ 10 'regressiontests.file_uploads.*': 'regressiontests.file_uploads.backends.TestFileBackend', 11 }) 8 12 9 13 class FileModel(models.Model): 10 testfile = models.FileField( storage=temp_storage,upload_to='test_upload')14 testfile = models.FileField(upload_to='test_upload') -
tests/regressiontests/file_uploads/tests.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/tests.py
a b 5 5 import unittest 6 6 from StringIO import StringIO 7 7 8 from django.conf import settings 8 9 from django.core.files import temp as tempfile 9 10 from django.core.files.uploadedfile import SimpleUploadedFile 10 11 from django.test import TestCase, client … … 17 18 18 19 UNICODE_FILENAME = u'test-0123456789_中文_Orléans.jpg' 19 20 21 class FileBackendTests(TestCase): 22 def setUp(self): 23 if not os.path.isdir(temp_storage.location): 24 os.makedirs(temp_storage.location) 25 if os.path.isdir(UPLOAD_TO): 26 shutil.rmtree(UPLOAD_TO) 27 28 def tearDown(self): 29 shutil.rmtree(temp_storage.location) 30 31 def test_prepare_upload(self): 32 response = self.client.get('/file_uploads/prepare_upload/') 33 self.assertEqual(response.status_code, 200) 34 data = simplejson.loads(response.content) 35 self.assertEqual(data, [ 36 '/redirect/file_uploads/prepare_upload/', [ 37 '<input type="file" name="testfile" id="id_testfile" />', 38 '<input type="hidden" name="x-data" value="efg" id="id_x-data" />', 39 '<input type="hidden" name="x-extra" value="abcd" id="id_x-extra" />', 40 ] 41 ]) 42 43 def test_serve_file(self): 44 obj = FileModel() 45 obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', 'x')) 46 obj.save() 47 response = self.client.get('/file_uploads/serve/') 48 self.assertEqual(response.status_code, 302) 49 self.assertEqual(response['Location'], 'http://testserver/download/') 50 51 def test_serve_file_fallback(self): 52 obj = FileModel() 53 obj.testfile.save('foo.pass', SimpleUploadedFile('foo.pass', 'x')) 54 obj.save() 55 response = self.client.get('/file_uploads/serve/') 56 self.assertEqual(response.status_code, 200) 57 58 def test_download_url(self): 59 obj = FileModel() 60 obj.testfile.save('foo2.txt', SimpleUploadedFile('foo2.txt', 'x')) 61 obj.save() 62 url = obj.testfile.download_url() 63 self.assertEqual(url, '/public/') 64 65 def test_download_url_fallback(self): 66 obj = FileModel() 67 obj.testfile.save('foo2.pass', SimpleUploadedFile('foo2.pass', 'x')) 68 obj.save() 69 url = obj.testfile.download_url() 70 self.assertEqual(url, settings.MEDIA_URL + obj.testfile.name) 71 20 72 class FileUploadTests(TestCase): 21 73 def test_simple_upload(self): 22 74 post_data = { … … 122 174 response = self.client.request(**r) 123 175 124 176 # The filenames should have been sanitized by the time it got to the view. 125 rec ieved = simplejson.loads(response.content)177 received = simplejson.loads(response.content) 126 178 for i, name in enumerate(scary_file_names): 127 got = rec ieved["file%s" % i]179 got = received["file%s" % i] 128 180 self.assertEqual(got, "hax0rd.txt") 129 181 130 182 def test_filename_overflow(self): -
tests/regressiontests/file_uploads/urls.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/urls.py
a b 10 10 (r'^quota/broken/$', views.file_upload_quota_broken), 11 11 (r'^getlist_count/$', views.file_upload_getlist_count), 12 12 (r'^upload_errors/$', views.file_upload_errors), 13 (r'^prepare_upload/$', views.file_prepare_upload), 14 (r'^serve/$', views.file_serve), 13 15 ) -
tests/regressiontests/file_uploads/views.py
diff -r c8038a5c808d tests/regressiontests/file_uploads/views.py
a b 2 2 from django.core.files.uploadedfile import UploadedFile 3 3 from django.http import HttpResponse, HttpResponseServerError 4 4 from django.utils import simplejson 5 from forms import FileForm 5 6 from models import FileModel, UPLOAD_TO 6 7 from uploadhandler import QuotaUploadHandler, ErroringUploadHandler 7 8 from django.utils.hashcompat import sha_constructor … … 112 113 def file_upload_errors(request): 113 114 request.upload_handlers.insert(0, ErroringUploadHandler()) 114 115 return file_upload_echo(request) 116 117 def file_prepare_upload(request): 118 form = FileForm(request) 119 return HttpResponse(simplejson.dumps([form.url, list(map(unicode, form))])) 120 121 def file_serve(request): 122 return FileModel.objects.all()[0].testfile.serve(request)