Work in progress {{{ # models.py class SomeFile(models.Model): description = models.CharField(maxlength=255) file = models.FileField(upload_to='files') }}} {{{ # manipulators.py from models import SomeFile from django import forms from django.conf import settings class AddFileManipulator(forms.Manipulator): def __init__(self): self.fields = ( forms.TextField(field_name="description", length=30, maxlength=200, is_required=True), MyFileUploadField(field_name="file", is_required=True) ) def do_html2python(self, new_data): new_new_data = {} new_new_data['file_path'] = os.path.join(settings.MEDIA_ROOT, filename) os.rename(new_data['file'], new_new_data['file_path']) new_new_data['description'] = new_data['description'] new_data = new_new_data def save(self, new_data): new_object = SomeField(**new_data) new_object.save() }}} {{{ # views.py from manipulators import def upload_file(request): manipulator = AddFileManipulator() if request.method == 'POST': # If data was POSTed, we're trying to create a new Place. new_data = request.POST.copy() new_data.update(request.FILES) # Check for errors. errors = manipulator.get_validation_errors(new_data) if not errors: # No errors. This means we can save the data! manipulator.do_html2python(new_data) new_object = manipulator.save(new_data) # Redirect to the object's "edit" page. Always use a redirect # after POST data, so that reloads don't accidently create # duplicate entires, and so users don't see the confusing # "Repost POST data?" alert box in their browsers. return HttpResponseRedirect("/someurl/" % new_object.id) else: # No POST, so we want a brand new form without any data or errors. errors = new_data = {} # Create the FormWrapper, template, context, response. form = forms.FormWrapper(manipulator, new_data, errors) return render_to_response('add_file.html', {'form': form}) }}}