How it works...

If the JavaScript fails to execute, the form remains completely usable just as it was before, but when JavaScript runs properly, we get an enhanced form with the file field replaced by a simple button, as shown here:

When an image is selected by clicking on the Select Picture button, the result in the browser will look similar to the following screenshot:

Clicking on the Start button in this new row triggers the Ajax upload process, and we then see a preview of the image that has been attached, as shown in the following screenshot. We can see here that the upload-related action buttons are also replaced with a Remove button, which would trigger deletion of the uploaded file:

The same form will work using the normal file input if JavaScript somehow is unable to run as expected. Let's run backwards through the steps to dig deeper into the process and to see how it works.

In the changed form, we load the scripts and CSS that support the jQuery File Upload widget, as well as our own Uploader code. When the page is ready, we instantiate the Uploader that will enable the Ajax submission enhancements, providing it with a reference to the form element, the URL corresponding to our upload view, and translated labels for each of the action buttons.

As part of functionality given by the JavaScript templates utilities, the translation dictionary keys will serve as fallback values, if the translation is invalid.

The Uploader is where the majority of the work happens. When initialized, it goes through a series of steps, as follows:

  • Processing and merging any provided options with the DEFAULTS
  • Gathering the elements within the form that are needed for handling uploads—specifically, the csrfmiddlewaretoken hidden field, the picture file input field, and the picture_path hidden field
  • Dynamically creating the Select <button> element and a container <table> that will hold the uploaded files list
  • Wrapping the file input in the Select button and adding the container above it
  • Setting up the jQuery File Upload widget

The really interesting work happens in this final step. We'll dive a bit deeper into that here:

  • First, the X-CSRFToken header is set by default in the Ajax settings, so that the upload and delete requests will be accepted.
  • Next, the widget is initialized for the form. Settings such as the upload URL, acceptable MIME types, and translated labels are passed along.
  • And last, but not least, event listeners are set up to update the picture_path field value properly when an image has either been uploaded or removed. These listen for the fileuploaddone and fileuploaddestroy custom widget events, which correspond respectively to those two actions, but there are many other events available, too.

On page load, the Uploader is initialized and Ajax enhancements are applied. When a user clicks on the Select button, the file input is triggered and the usual file selection window opens. After selection, a row is added to the files list using the content provided by the tmpl_upload.html include, which shows the filename, human-friendly file size, and the action buttons. If the user clicks the Cancel button, that row is removed without ever uploading the file.

After clicking the Start button, the Ajax upload request kicks off, and the upload view stores the image under the UPLOAD_ROOT, returning the appropriate JSON data as generated from the upload.json template. This data is used to replace the existing file row with a new one generated from the tmpl_download.html include. The new row contains a preview thumbnail, the filename, the file size, and a Remove button.

Examining the two JavaScript template includes more closely, we can see that their content is wrapped by {% verbatim %} Django template tags. This is done because the JavaScript template syntax is very similar to the core Django template syntax, and it would confuse Django and cause errors. Similarly to Django, there are {% ... %} tags that can contain JavaScript expressions, and we can use {%=... %} to output variables. By default, context data is nested under a global o variable.

The outermost tag in the includes initiates a loop over a files list in that context data. This list corresponds to the list created in the JSON returned by the upload and delete views. As we can see, the upload.json also uses a loop to generate its content, so it would be trivial to use a similar implementation to handle a multiple-image case.

In the delete_quote_picture view, a valid Ajax request should use the DELETE method, and the filename to be deleted is parameterized as part of the URL. We use the same upload storage system that initially saves the images in order to delete them. The view always returns a valid JSON object containing an empty file list, so the form will update to remove the uploaded image, even if there is an issue with the server.

As for the upload_quote_picture view, there is more strict processing, and by default, we assume a bad request. When the request itself is valid, we reinforce the image type restrictions on the server, which is always a good practice. For valid types, we save the picture using the upload storage system, and add the result to the files list. We also dynamically add a filename property containing only the base name of the file, to pass along and ultimately display in the file list.

After a picture has been selected and uploaded, and the form is submitted, the quote instance will be saved initially with no picture. In the custom save-handling for the form, though, we check for a picture_path, which would indicate that an upload took place. Using the same upload storage, we open the given path and save that as the picture for the quote. Afterward, since the uploaded image is no longer needed, it is deleted. Any changes are saved back to the instance, which is then returned.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.23.30