Skip to content

Ajax-based, multiple-upload django class with pluggable backends, and subclass goodness.

License

Notifications You must be signed in to change notification settings

chrisjones-brack3t/django-ajax-uploader

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

django-ajax-uploader provides a useful class you can use to easily implement ajax uploads.

It uses valum's great uploader: https://github.com/valums/file-uploader, and draws heavy inspiration and some code from https://github.com/alexkuhl/file-uploader

In short, it implements a callable class, AjaxFileUploader that you can use to handle uploads. By default, AjaxFileUploader assumes you want to upload to local storage, but you can select any other backend if desired or write your own (see backends section below). Pull requests welcome!

Usage

Step 1. Install django-ajax-uploader.

Right now, you can either:

  • Download and install, or
  • pip install -e git://github.com/chrisjones-brack3t/django-ajax-uploader.git#egg=ajaxuploader it from here. If there's demand, I'll look into pypi.
  • If you plan on using the Amazon S3 backend you will also need to install boto
$ pip install boto
  • If you plan on using the MongoDB GridFS backend you will also need to install pymongo
$ pip install pymongo

Step 2. (Django 1.3 only)

For Django 1.3 you will need to have the app in your installed apps tuple for collect static to pick up the files.

First Add 'ajaxuploader' to you installed apps in settings.py

INSTALLED_APPS = (
    ...
    "ajaxuploader",
)

Then:

$ python manage.py collectstatic

Step 3. Include it in your app's views and urls.

You'll need to make sure to meet the csrf requirements to still make valum's uploader work. Code similar to the following should work:

views.py

from django.shortcuts import render
from ajaxuploader.views import AjaxFileUploader
from django.middleware.csrf import get_token

def start(request):
    csrf_token = get_token(request)
    return render(request, 'import.html',
        {'csrf_token': csrf_token})

import_uploader = AjaxFileUploader()

urls.py

url(r'ajax-upload$', views.import_uploader, name="my_ajax_upload"),

Step 4. Set up your template.

This sample is included in the templates directory, but at the minimum, you need:

<!doctype html>
    <head>
        <script src="{{ STATIC_URL }}django-ajax-uploader/fileuploader.js" ></script>
        <link href="{{ STATIC_URL }}django-ajax-uploader/fileuploader.css" media="screen" rel="stylesheet" type="text/css" />
        <script>
            var uploader = new qq.FileUploader({
                action: "{% url my_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>Please enable JavaScript to use file uploader.</p>
        </noscript>         
    </div>
</body>
</html>

Backends

django-ajax-uploader can put the uploaded files into a number of places, and perform actions on the files uploaded. Currently, there are backends available for local storage (default), Amazon S3 and MongoDB (GridFS), as well as a locally stored image thumbnail backend. Creating a custom backend is fairly straightforward, and pull requests are welcome.

Built-in Backends

django-ajax-uploader has the following backends:

local.LocalUploadBackend

Stores the file locally, by default to {MEDIA_ROOT}/uploads.

Requirements:

  • None

Settings:

  • UPLOAD_DIR : The directory to store the uploaded file in, within MEDIA_ROOT. Defaults to "uploads".
  • BUFFER_SIZE: The size of each chunk to write. Defaults to 10 MB. See the caveat at the bottom before changing it.

Context returned:

  • path: The full media path to the uploaded file.

mongodb.MongoDBUploadBackend

Stores the file in MongoDB via GridFS

Requirements

Settings:

  • AJAXUPLOAD_MONGODB_HOST: Specify the host of your MongoDB server. Defaults to localhost if not specified.
  • AJAXUPLOAD_MONGODB_PORT: Specify the port of your MongoDB server. Defaults to 27017 if not specified.

Arguments

  • db (required): Specify the database within MongoDB you wish to use
  • collection (optional): Specify the collection within the db you wish to use. This is optional and will default to fs if not specified

Context returned:

  • None

s3.S3UploadBackend

Stores the file in Amazon's S3.

Requirements:

Settings:

  • NUM_PARALLEL_PROCESSES : Uploads to Amazon are parallelized to increase speed. If you have more cores and a big pipe, increase this setting for better performance. Defaults to 4.
  • BUFFER_SIZE: The size of each chunk to write. Defaults to 10 MB.

Context returned:

  • None

s3.S3UploadBackend

Stores a thumbnail of the locally, optionally discarding the upload. Subclasses LocalUploadBackend.

Requirements:

Settings:

  • DIMENSIONS : A string of the dimensions (WxH) to resize the uploaded image to. Defaults to "100x100"
  • KEEP_ORIGINAL: Whether to keep the originally uploaded file. Defaults to False.
  • BUFFER_SIZE: The size of each chunk to write. Defaults to 10 MB.

Context returned:

  • path: The full media path to the uploaded file.

Backend Usage

The default backend is local.LocalUploadBackend. To use another backend, specify it when instantiating AjaxFileUploader.

For instance, to use MongoDBUploadBackend:

views.py

from ajaxuploader.views import AjaxFileUploader
from ajaxuploader.backends.mongodb import MongoDBUploadBackend

...
import_uploader = AjaxFileUploader(backend=MongoDBUploadBackend, db='uploads')

To set custom parameters, simply pass them along with instantiation. For example, for larger thumbnails, preserving the originals: views.py

from ajaxuploader.backends.thumbnail import ThumbnailUploadBackend

...
import_uploader = AjaxFileUploader(backend=ThumbnailUploadBackend, DIMENSIONS="500x500", KEEP_ORIGINAL=True)

Custom Backends

To write a custom backend, simply inherit from backends.base.AbstractUploadBackend and implement the upload_chunk method. All possible methods to override are described below.

  • upload_chunk - takes a string, and writes it to the specified location.
  • setup: takes the original filename, does all pre-processing needed before uploading the file (for example, for the S3 backend, this method is used to establish a connection with the S3 server).
  • update_filename: takes the request object and the original name of the file being updated, can return a new filename which will be used to refer to the file being saved. If undefined, the uploaded filename is used. If not overriden by upload_complete, this value will be returned in the response.
  • upload_complete: receives the request object and the filename post update_filename and does any cleanup or manipulation after the upload is complete. (Examples: cropping the image, disconnecting from the server). If a dict is returned, it is used to update the response returned to the client.

Caveats

BUFFER_SIZE - some users have reported problems using smaller buffer sizes. I also saw random failed uploads with very small sizes like 32k. 10MB has been completely reliable for me, and in what I've read here and there, so do some testing if you want to try a different value. Note that this doesn't have a big impact on the overall upload speed.

Credits

Most of the backend abstraction was written by chromano and shockflash.

This code began as such a trivial layer on top of valum's uploader, boto, and alex's ideas it's silly. However, I didn't find any implementations that just worked, so hopefully it's useful to someone else. I also drew from these sources:

Many thanks to all for writing such helpful and readable code!

About

Ajax-based, multiple-upload django class with pluggable backends, and subclass goodness.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 83.8%
  • Python 16.2%