Skip to content

Django-file-form helps you to write forms with a pretty ajax upload

License

Notifications You must be signed in to change notification settings

OpenTechFund/django-file-form

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Version

Coverage Status Requirements Status

License

Django file form

Django-file-form helps you to write forms with a pretty ajax upload.

Features:

  • You can easily add an ajax file-upload to a form.
  • The ajax upload works the same as an html upload.
    • This means that you don't have to change your code to support ajax upload.
  • Supports single and multiple file upload.

The project is hosted on github.

Works with Django 2.0 - 3.0. Also with Python 3.6 - 3.8

Older versions:

  • 1.0.1 uses fine uploader for the javascript part
  • 0.5.0 supports Django 1.11 and Python 2.

Version 2.0 has changed: see 'Upgrade from version 1.0' below, if you're upgrading from version 1.0 (or lower).

Usage

1 Install django-file-form

pip install django-file-form

2 Add the apps to your INSTALLED_APPS

You must include 'django_file_form'

INSTALLED_APPS = [
    'django_file_form',
]

3 Add the app to your urls

In this example we use the url upload/. You can use a different url if you like.

urlpatterns = patterns(
    '',
    url(r'^upload/', include('django_file_form.urls')),
)

4 Add FileFormMixin to your form

from django_file_form.forms import FileFormMixin

class ExampleForm(FileFormMixin, forms.Form):
    pass

5 Add a UploadedFileField

from django_file_form.forms import FileFormMixin, UploadedFileField

class ExampleForm(FileFormMixin, forms.Form):
    input_file = UploadedFileField()

Import and use MultipleUploadedFileField if you intent to add multiple files.

6 Include javascript and css in your template

<script src="{% static "file_form/file_form.js" %}"></script>
<link rel="stylesheet" href="{% static "file_form/file_form.css" %}">

There is also an uncompressed javascript version: file_form/file_form.debug.js.

7 Call the initUploadFields javascript function

<form id="example-form" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form }}
</form>

<script>
   initUploadFields(
      document.getElementById("example-form")
   );
</script>

If your form has a prefix, then call initUploadFields as follows:

  // for example, with prefix 'abc'
  initUploadFields(
    document.getElementById("example-form"),
    { prefix: 'abc' }
  );

See the Django documentation for more information about form prefixes.

8 Handle uploaded files

class ExampleFormView(generic.FormView):
    template_name = 'example_form.html'
    form_class = forms.ExampleForm

    def form_valid(self, form):
        input_file = form.cleaned_data['input_file']

        return super(ExampleFormView, self).form_valid(form)

9 Delete temporary files

class ExampleFormView(generic.FormView):
    template_name = 'example_form.html'
    form_class = forms.ExampleForm

    def form_valid(self, form):
        input_file = form.cleaned_data['input_file']

        form.delete_temporary_files()

        return super(ExampleFormView, self).form_valid(form)

Details

1 Include hidden fields

Make sure that hidden form fields are included:

{% for hidden in form.hidden_fields %}
    {{ hidden }}
{% endfor %}

NB: it's possible that the hidden fields are already included; for example if you use form.as_p. Do not include the hidden fields twice.

Also see the testproject in the repository.

2 Temp upload dir must exist

Make sure the FILE_FORM_UPLOAD_DIR directory exists.

temp_upload_dir = os.path.join(settings.MEDIA_ROOT,  settings.FILE_FORM_UPLOAD_DIR)

if not os.path.exists(temp_upload_dir):
  os.mkdir(temp_upload_dir)

3 Adding placeholder files

If you have used django-file-form to upload files, potentially have saved the files elsewhere, but would like to use django-file-form to edit (remove or replace) the original uploaded files and append new files, you can add information about the original uploaded files as placeholders to the UploadedFileField. More specifically, you can initialize your field with one or more PlaceholderUploadedFile as follows:

from django_file_form.models import PlaceholderUploadedFile

initial['my_field'] = [
  PlaceholderUploadedFile('manage.py')
]

You can also add options size and file_id to specify file size if the file does not exist locally, and an unique ID of the file, respectively.

initial['my_field'] = [
  PlaceholderUploadedFile('manage.py', size=12394, file_id=my_file.pk)
]

The placeholder file will be listed, and will either be kept intact, or be removed. When you save the form, you will have to handle the placeholders as follows:

for f in self.cleaned_data['my_field']:
    if f.is_placeholder:
        # do nothing, or something with f.name or f.file_id
        continue
    # handle newly uploaded files as usual

# remove existing files if the placeholders are deleted
# ...

Upgrade from version 1.0 (to 2.0)

  • Add reference to file_form/file_form.css:
    • <link rel="stylesheet" href="{% static "file_form/file_form.css" %}">
  • Remove django_file_form.ajaxuploader from INSTALLED_APPS in your settings
  • Remove reference to ajaxuploader/js/fileuploader.js in your template
  • Remove reference to ajaxuploader/css/fileuploader.css in your template
  • You don't have to include jquery; the fileuploader doesn't use it
  • The setting FILE_FORM_UPLOAD_BACKEND is removed
  • If you use custom css, you might have to change it.
    • The html uses the prefix dff now.

Settings

Settings in settings.py:

  • FILE_FORM_MUST_LOGIN (True / False):

    • Must the user be logged in to upload a file.
    • The default is False.
  • FILE_FORM_UPLOAD_DIR (string):

    • The directory for the temporary uploads.
    • The setting is relative to MEDIA_ROOT.
    • The default is temp_uploads.
  • FILE_FORM_MAX_FILE_SIZE (int)

    • Maximum upload size in bytes
    • Default is 4GB
  • FILE_FORM_FILE_STORAGE (string):

    • Dotted path to the class that is used to store temporary uploads.
    • The default is django.core.files.storage.FileSystemStorage.
    • Note that files will be uploaded to the local file system first regardless. This storage backend will be used only for fully uploaded files that are then passed back to the form when it's submitted.
  • FILE_FORM_CACHE (string):

    • Name of a cache backend defined in settings.CACHES.
    • The default is Django's default cache.
    • The cache is used to store data about files while they are being uploaded. If the default might be cleared while a file upload is in progress then using a different backend like django's database cache might be more appropriate. Note that cache.clear() will clear the whole cache at a specified LOCATION regardless what the KEY_PREFIX is.

initUploadFields

Signature of initUploadFields is:

initUploadFields(formDomElement, options);
  • formDomElement (required); e.g. document.getElementById("example-form")
  • options (optional)
    • callbacks: callbacks for things like upload progress and errors.
    • prefix : set this if the Django form has a prefix; default is empty
    • retryDelays: set retry delays
      • Also see https://github.com/tus/tus-js-client#tusdefaultoptions
      • Default is [0, 1000, 3000, 5000]
    • skipRequired : don't set the required field of the file input; default is false
    • supportDropArea : add a drop area; default is true

The callbacks are:

  • onDelete
    • called when file is deleted
    • Signature of callback is function(upload)
  • onError:
    • called when an upload error occurs
    • Signature of callback is function(error, upload)
      • error: javascript Error
  • onProgress:
    • Called each time when progress information is available.
    • Signature of callback is function(bytesUploaded, bytesTotal, upload)
  • onSuccess:
    • Called when file upload is done.
    • Signature of callback is function(upload)

The callbacks receive an upload parameter which is this class.

Examples:

initUploadFields(
  document.getElementById("example-form")
);
initUploadFields(
  document.getElementById("example-form"),
  {
    prefix: "example",
    skipRequired: true,
    supportDropArea: true
  }
);

Form sets

You can also use a form set instead of a form. In that case initFormSet (instead of initUploadFields) in your javascript code.

initFormSet(form_element, options)
initFormSet(
  document.getElementById("example-form"),
  { prefix: "form" }
);
  • Note that the default form set prefix is form.
  • Also see the testproject directory in the repository for an example.

Translate

To update a translation or add new language

Fork this repo as usual

# enter in project folder
cd django-file-form

# create virtualenv (example using pipenv)
pipenv install --python=3 -r testproject/requirements.txt

# enter in venv shell
pipenv shell

# update po file for your language
django-admin makemessages -l fr

You can now edit generated po file and commit your changes as usual

Changelog

  • 2.2.0 (july 22 2020)

    • Issue #315: file is not removed after form error
    • Issue #313: allow using custom storage and custom cache (thanks to Balazs Endresz)
  • 2.1.3 (20 june 2020)

    • Issue #304: rewrite frontend in typescript
    • Issue #305: don't change migration when setting changes (thanks to Lionqueen94)
    • Issue #307: add French translations; also make translations discoverable by makemessages (thanks to Simon Maillard)
  • 2.1.2 (20 april 2020)

    • Issue #298: directory support for drop area
    • Issue #300: add migration so makemigrations will not create one (thanks to Lionqueen94)
  • 2.1.1 (7 april 2020)

    • Issue #290: add javascript callbacks (thanks to Peter Dekkers)
    • Issue #296: fix progress bar
    • Issue #297: add retry delays
  • 2.1.0 (28 march 2020)

    • Issue #266: allow relative FILE_FORM_UPLOAD_DIR setting (thanks to Bo Peng)
    • Issue #267: add drop area (thanks to Bo Peng)
    • Issue #275: show size of uploaded files (thanks to Bo Peng)
    • Issue #278: allow the addition of placeholder files (thanks to Bo Peng)
    • Issue #280: remove option FILE_FORM_FILE_STORAGE
  • 2.0.3 (15 february 2020)

    • Issue #237: using with form set (thanks to Juan Carlos Carvajal)
    • Issue #259: include uncompressed js
    • Issue #260: correctly use formset prefix (thanks to Gzuba)
    • Issue #261: fix default for FILE_FORM_UPLOAD_DIR (thanks to Gzuba)
  • 2.0.2 (14 january 2020)

    • Issue #247: support form wizard (thanks to Lionqueen94)
    • Issue #251: delete after submit
  • 2.0.1 (6 january 2020)

    • Issue #240: add empty dff files div (thanks to Lionqueen94)
    • Issue #241: Csp compliance (thanks to Lionqueen94)
  • 2.0 (30 december 2019)

    • Use tus instead of fine uploader
  • 1.0 (5 december 2019)

    • Drop support for Python 2 and Django < 2
    • Issue #217: update fine uploader
    • Issue #219: use Selenium for all tests
    • Issue #222: use pathlib2 (instead of pathlib)
    • Issue #235: support Django 3.0
  • 0.4.2 (3 March 2019)

    • Issue #207: support form prefixes (thanks to Iw108)
    • Issue #201: fix multiple file upload without ajax (thanks to Lionqueen94)
  • 0.4.1 (5 January 2019)

    • Issue #194: correctly call is_authenticated (thanks to Dureba)
  • 0.4.0 (3 August 2018)

    • Support Django 2.1 and Python 3.7
    • Issue #173: add i18n to upload widget (thanks to Arman Roomana)
  • 0.3.0 (6 December 2017)

    • Support Django 2.0

About

Django-file-form helps you to write forms with a pretty ajax upload

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 63.1%
  • Python 26.7%
  • TypeScript 8.2%
  • HTML 1.2%
  • CSS 0.8%