Source code for superdjango.views.ajax.views

# Imports

from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse, HttpResponseBadRequest, Http404, HttpResponseNotAllowed
import json
from superdjango.storage.backends.ajax.local import LocalAjaxStorage
from superdjango.storage.signals import ajax_file_uploaded

# Exports

__all__ = (
    "AjaxFileUploader",
)

# Classes


[docs]class AjaxFileUploader(object): """This pseudo-view class provides support for uploading files via AJAX. **Setup** The JavaScript files for AJAX upload are located in the assets app, so make sure you have this in your ``settings.py`` file: .. code-block:: python INSTALL_APPS = [ # ... "superdjango.assets.apps.DefaultConfig", # ... ] **Usage** Create a view for handling the upload. In the example below, the `ajax_uploader` view is initialized (without any options) at the bottom of the file. The ``upload_form()`` view is used to present an AJAX-enabled upload form. You may wish to integrate this into your own form view and template instead. .. code-block:: python from django.middleware.csrf import get_token from django.shortcuts import render_to_response from django.template import RequestContext from superdjango.ajax.uploads.views import AjaxFileUploader def upload_form(request): csrf_token = get_token(request) return render_to_response( 'upload_form.html', {'csrf_token': csrf_token}, context_instance=RequestContext(request) ) ajax_uploader = AjaxFileUploader() Add the views to your main ``urls.py`` file: .. code-block:: python from superdjango.ajax import views as ajax_upload_views urlpatterns = [ # ... path(r'ajax/upload/start/)', ajax_upload_views.upload_form, name="upload_form"), path(r'ajax/upload/', ajax_upload_views.import_uploader, name="ajax_upload"), # ... ] Create a template or add to the template where the upload should occur: .. code-block:: html {% load i18n %} {% load static %} <!doctype html> <head> <script src="{% static "bundled/fileuploader/js/fileuploader.js" %}" ></script> <link href="{% static "bundled/fileuploader/css/fileuploader.css" %}" rel="stylesheet" /> <script> $(function(){ var uploader = new qq.FileUploader({ action: "{% url ajax_upload %}", element: $('#file-uploader')[0], multiple: true, onComplete: function(id, fileName, responseJSON) { if (responseJSON.success) { alert("success!"); } else { alert("upload failed!"); } }, onAllComplete: function(uploads) { // uploads is an array of maps // the maps look like this: {file: FileObject, response: JSONServerResponse} alert("All complete!"); }, params: { 'csrf_token': '{{ csrf_token }}', 'csrf_name': 'csrfmiddlewaretoken', 'csrf_xname': 'X-CSRFToken', }, }); }); </script> </head> <body> <div id="file-uploader"> <noscript> <p>{% trans "Please enable JavaScript to use the file uploader." %}</p> </noscript> </div> </body> </html> """
[docs] def __init__(self, backend=None, **kwargs): """Initialize the view. :param backend: The backend class to use. Defaults to :py:class:`LocalAjaxStorage`. kwargs are passed to the backend upon instantiation. """ if backend is None: backend = LocalAjaxStorage self.get_backend = lambda: backend(**kwargs)
def __call__(self, request, *args, **kwargs): return self._ajax_upload(request, *args, **kwargs) def _ajax_upload(self, request, *args, **kwargs): if request.method == "POST": if request.is_ajax(): # the file is stored raw in the request upload = request is_raw = True # AJAX Upload will pass the filename in the querystring if it # is the "advanced" ajax upload try: if 'qqfile' in request.GET: filename = request.GET['qqfile'] else: filename = request.REQUEST['qqfilename'] except KeyError: return HttpResponseBadRequest("AJAX request not valid") # not an ajax upload, so it was the "basic" iframe version with # submission via form else: is_raw = False if len(request.FILES) == 1: # FILES is a dictionary in Django but Ajax Upload gives # the uploaded file an ID based on a random number, so it # cannot be guessed here in the code. Rather than editing # Ajax Upload to pass the ID in the querystring, observe # that each upload is a separate request, so FILES should # only have one entry. Thus, we can just grab the first # (and only) value in the dict. upload = request.FILES.values()[0] else: raise Http404("Bad Upload") filename = upload.name backend = self.get_backend() # custom filename handler filename = (backend.update_filename(request, filename, *args, **kwargs) or filename) # save the file backend.setup(filename, *args, **kwargs) success = backend.upload(upload, filename, is_raw, *args, **kwargs) if success: ajax_file_uploaded.send(sender=self.__class__, backend=backend, request=request) # callback extra_context = backend.upload_complete(request, filename, *args, **kwargs) # let Ajax Upload know whether we saved it or not ret_json = {'success': success, 'filename': filename} if extra_context is not None: ret_json.update(extra_context) # although "application/json" is the correct content type, IE throws a fit return HttpResponse(json.dumps(ret_json, cls=DjangoJSONEncoder), content_type='text/html; charset=utf-8') else: response = HttpResponseNotAllowed(['POST']) response.write("ERROR: Only POST allowed") return response