Login

Upload a file using newforms

Author:
mboersma
Posted:
March 9, 2007
Language:
Python
Version:
Pre .96
Tags:
django newforms files forms
Score:
8 (after 8 ratings)

Django's transition from oldforms to newforms is nearing. If you're using recent trunk source code from Django's subversion repository, you should start using newforms.

But there are still some rough edges as of today. File uploading seems to be one of them. (Adrian and other Django folks are well aware of this. Please don't bother them by asking "Are we there yet?")

The Django mailing lists and Google searching didn't turn up any best practices for this area of newforms, so I muddled through it and here's the result. I omit the urls.py code necessary to hook up the zip_upload method to a URL, but otherwise this should be complete.

And if I haven't loaded this with enough caveats...please be aware this code may be obsoleted soon.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python

"""Please be aware this code is a stopgap measure that should go away when
more complete support for file uploading is added to newforms.

This demonstrates one way to do HTTP file upload using Django's groovy
new "newforms" approach.  There isn't a FileField-type class for newforms
yet (as of March 9th, 2007), so you must do some additional work to fetch
the uploaded content."""


try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
import zipfile

from django import http
from django import newforms as forms
from django.shortcuts import render_to_response
from django.contrib.auth.decorators import login_required

# You will probably want to work with one or more of your model classes.
#from mysite.pix.models import Picture


class ZipUploadForm(forms.Form):
    """A django.newforms class that uses a FileInput widget to accept
    uploaded .ZIP files."""

    zip_file = forms.Field(widget=forms.FileInput())
    owner = forms.CharField(max_length=80)

    def clean_zipfile(self):
        if 'zip_file' in self.clean_data:
            zip_file = self.clean_data['zip_file']
            if zip_file.get('content-type') != 'application/zip':
                msg = 'Only .ZIP archive files are allowed.'
                raise forms.ValidationError(msg)
            else:
                # Verify that it's a valid zipfile
                zip = zipfile.ZipFile(StringIO(zip_file['content']))
                bad_file = zip.testzip()
                zip.close()
                del zip
                if bad_file:
                    msg = '"%s" in the .ZIP archive is corrupt.' % (bad_file,)
                    raise forms.ValidationError(msg)
            return zip_file

    def save(self):
        owner = self.clean_data['owner']
        zipdata = self.clean_data['zip_file']['content']
        zip = zipfile.ZipFile(StringIO.StringIO(zipdata))
        for filename in zip.namelist():
            # Do something here with each file in the .ZIP archive.
            #
            # For example, if you expect the archive to contain image
            # files, you could process each one with PIL, then create
            # and populate your models.Picture object and save it.
            #data = zip.read(filename)
            #pic = Picture(owner, filename, data)
            #pic.save()
            pass
        zip.close()


@login_required
def zip_upload(request, template='zipupload.html'):

    form = None

    # Typically, we'd do a permissions check here.
    #if not request.user.has_perm('pix.add_picture'):
    #    return http.HttpResponseForbidden('You cannot add pictures.')

    if request.POST:
        post_data = request.POST.copy()
        post_data.update(request.FILES)
        form = ZipUploadForm(post_data)
        if form.is_valid():
            success = form.save()
            return http.HttpResponseRedirect('/pix/upload_success/')
    else:
        form = ZipUploadForm()
    return render_to_response(template, {'form':form})



# Example template for "zipupload.html"
{% extends "base.html" %}

{% block content %}
  <div class="content">
    <h1>Upload a .Zip file</h1>
    <div class="body">
      <p>
        <form action="/zip_upload/" method="post"
              enctype="multipart/form-data">
          <table>
            {{ form }}
          </table>
          <input type="submit" value="Upload ZIP" />
        </form>
      </p><br />
      <p>Some helpful text really should go here.</p>
    </div>
  </div>
{% endblock %}

More like this

Comments

Magus (on February 11, 2008):

This snippet is out of date - newforms now supports file uploads on its own, and does not require you to write your own support as in this snippet.

#

Please login first before commenting.