Hide keyboard shortcuts

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 

2 

3from django.core.serializers.json import DjangoJSONEncoder 

4from django.http import HttpResponse, HttpResponseBadRequest, Http404, HttpResponseNotAllowed 

5import json 

6from superdjango.storage.backends.ajax.local import LocalAjaxStorage 

7from superdjango.storage.signals import ajax_file_uploaded 

8 

9# Exports 

10 

11__all__ = ( 

12 "AjaxFileUploader", 

13) 

14 

15# Classes 

16 

17 

18class AjaxFileUploader(object): 

19 """This pseudo-view class provides support for uploading files via AJAX. 

20 

21 **Setup** 

22 

23 The JavaScript files for AJAX upload are located in the assets app, so make sure you have this in your 

24 ``settings.py`` file: 

25 

26 .. code-block:: python 

27 

28 INSTALL_APPS = [ 

29 # ... 

30 "superdjango.assets.apps.DefaultConfig", 

31 # ... 

32 ] 

33 

34 **Usage** 

35 

36 Create a view for handling the upload. In the example below, the `ajax_uploader` view is initialized (without any 

37 options) at the bottom of the file. The ``upload_form()`` view is used to present an AJAX-enabled upload form. You 

38 may wish to integrate this into your own form view and template instead. 

39 

40 .. code-block:: python 

41 

42 from django.middleware.csrf import get_token 

43 from django.shortcuts import render_to_response 

44 from django.template import RequestContext 

45 from superdjango.ajax.uploads.views import AjaxFileUploader 

46 

47 def upload_form(request): 

48 csrf_token = get_token(request) 

49 return render_to_response( 

50 'upload_form.html', 

51 {'csrf_token': csrf_token}, 

52 context_instance=RequestContext(request) 

53 ) 

54 

55 ajax_uploader = AjaxFileUploader() 

56 

57 Add the views to your main ``urls.py`` file: 

58 

59 .. code-block:: python 

60 

61 from superdjango.ajax import views as ajax_upload_views 

62 

63 urlpatterns = [ 

64 # ... 

65 path(r'ajax/upload/start/)', ajax_upload_views.upload_form, name="upload_form"), 

66 path(r'ajax/upload/', ajax_upload_views.import_uploader, name="ajax_upload"), 

67 # ... 

68 ] 

69 

70 Create a template or add to the template where the upload should occur: 

71 

72 .. code-block:: html 

73 

74 {% load i18n %} 

75 {% load static %} 

76 <!doctype html> 

77 <head> 

78 <script src="{% static "bundled/fileuploader/js/fileuploader.js" %}" ></script> 

79 <link href="{% static "bundled/fileuploader/css/fileuploader.css" %}" rel="stylesheet" /> 

80 <script> 

81 $(function(){ 

82 var uploader = new qq.FileUploader({ 

83 action: "{% url ajax_upload %}", 

84 element: $('#file-uploader')[0], 

85 multiple: true, 

86 onComplete: function(id, fileName, responseJSON) { 

87 if (responseJSON.success) { 

88 alert("success!"); 

89 } 

90 else { 

91 alert("upload failed!"); 

92 } 

93 }, 

94 onAllComplete: function(uploads) { 

95 // uploads is an array of maps 

96 // the maps look like this: {file: FileObject, response: JSONServerResponse} 

97 alert("All complete!"); 

98 }, 

99 params: { 

100 'csrf_token': '{{ csrf_token }}', 

101 'csrf_name': 'csrfmiddlewaretoken', 

102 'csrf_xname': 'X-CSRFToken', 

103 }, 

104 }); 

105 }); 

106 </script> 

107 </head> 

108 <body> 

109 <div id="file-uploader"> 

110 <noscript> 

111 <p>{% trans "Please enable JavaScript to use the file uploader." %}</p> 

112 </noscript> 

113 </div> 

114 </body> 

115 </html> 

116 

117 """ 

118 

119 def __init__(self, backend=None, **kwargs): 

120 """Initialize the view. 

121 

122 :param backend: The backend class to use. Defaults to :py:class:`LocalAjaxStorage`. 

123 

124 kwargs are passed to the backend upon instantiation. 

125 

126 """ 

127 if backend is None: 

128 backend = LocalAjaxStorage 

129 

130 self.get_backend = lambda: backend(**kwargs) 

131 

132 def __call__(self, request, *args, **kwargs): 

133 return self._ajax_upload(request, *args, **kwargs) 

134 

135 def _ajax_upload(self, request, *args, **kwargs): 

136 if request.method == "POST": 

137 if request.is_ajax(): 

138 # the file is stored raw in the request 

139 upload = request 

140 is_raw = True 

141 # AJAX Upload will pass the filename in the querystring if it 

142 # is the "advanced" ajax upload 

143 try: 

144 if 'qqfile' in request.GET: 

145 filename = request.GET['qqfile'] 

146 else: 

147 filename = request.REQUEST['qqfilename'] 

148 except KeyError: 

149 return HttpResponseBadRequest("AJAX request not valid") 

150 # not an ajax upload, so it was the "basic" iframe version with 

151 # submission via form 

152 else: 

153 is_raw = False 

154 if len(request.FILES) == 1: 

155 # FILES is a dictionary in Django but Ajax Upload gives 

156 # the uploaded file an ID based on a random number, so it 

157 # cannot be guessed here in the code. Rather than editing 

158 # Ajax Upload to pass the ID in the querystring, observe 

159 # that each upload is a separate request, so FILES should 

160 # only have one entry. Thus, we can just grab the first 

161 # (and only) value in the dict. 

162 upload = request.FILES.values()[0] 

163 else: 

164 raise Http404("Bad Upload") 

165 

166 filename = upload.name 

167 

168 backend = self.get_backend() 

169 

170 # custom filename handler 

171 filename = (backend.update_filename(request, filename, *args, **kwargs) 

172 or filename) 

173 # save the file 

174 backend.setup(filename, *args, **kwargs) 

175 success = backend.upload(upload, filename, is_raw, *args, **kwargs) 

176 

177 if success: 

178 ajax_file_uploaded.send(sender=self.__class__, backend=backend, request=request) 

179 

180 # callback 

181 extra_context = backend.upload_complete(request, filename, *args, **kwargs) 

182 

183 # let Ajax Upload know whether we saved it or not 

184 ret_json = {'success': success, 'filename': filename} 

185 if extra_context is not None: 

186 ret_json.update(extra_context) 

187 

188 # although "application/json" is the correct content type, IE throws a fit 

189 return HttpResponse(json.dumps(ret_json, cls=DjangoJSONEncoder), content_type='text/html; charset=utf-8') 

190 else: 

191 response = HttpResponseNotAllowed(['POST']) 

192 response.write("ERROR: Only POST allowed") 

193 return response