As part of the ongoing improvements to the web site http://www.rc-stats.com/, I have decided that I want contributors to be able to upload race results. Currently I am using a python script to upload the results myself.
Some Back Ground on The Current Process
Currently I use set of python scripts and pgdb to parse the race results and feed them into the postgresql database. The code to feed results into the database was a bit rough and certainly not robust enough enough for contributors to work with (it has been a bit of bootstrapping as I learned more about security with respect to django and postgresql).
This was a design decision I made early on. That I would prioritize getting results into the system quickly, the consequence being that I would need to manually run script to upload races results every time they became available. Now that the site is live and I am able to start getting user feedback, the time has come for me to clean up this process.
References To Start From
- Django guide: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/?from=olddocs
- Stackoverflow description: http://stackoverflow.com/questions/5871730/need-a-minimal-django-file-upload-example
Initial Prototype
Using the django documentation and some stackoverflow examples I arrived at the following code.
upload_start.html
{% extends "base.html" %} {% block pagetitle %}Upload Race Results{% endblock %} {% block pagetitle_description %}Upload race results from the scoring system.{% endblock %} {% block content %} <section class="full_width"> <h2>{{ error_status }}</h2> <form action="/upload_start/" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="file" /> <input type="submit" name="submit" value="Upload" /> </form> {{ form.errors }} {{ form.non_field_errors }} </section><!-- /.full_width --> {% endblock %}
views.py
class UploadFileForm(forms.Form): #title = forms.CharField(max_length=50) file = forms.FileField() @login_required(login_url='/login') def upload_start(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) # What causes the form to not be valid? if form.is_valid(): # Need to make sure the key used for FILES[ ] matches up with the # form in the template. handle_uploaded_file(request.FILES['file']) return HttpResponseRedirect('/upload_start') else: error = "Failed to upload file:" + request.FILES['file'].name return render_to_response('upload_start.html', {'form':form, 'error_status': error}, context_instance=RequestContext(request)) else: form = UploadFileForm() return render_to_response('upload_start.html', {'form': form}, context_instance=RequestContext(request)) def handle_uploaded_file(f): #print "name:", f.name #print "size:", f.size with open('/home/username/Desktop/rcstats/rcdata_media/fileupload/testfile.txt', 'wb+') as destination: for chunk in f.chunks(): destination.write(chunk)
Some of the initial stumbling points I hit that are worth a note:
- I needed to have {% csrf_token %} added to the form, several older examples do not mention this.
- I was uncertain where the file should be written to, for the time being I have created a folder in the django media folder (I suspect this will need some revision when I get ready to run this on the live server).
- Apache needs permission to write to directory you plan to upload in. I used this reference to make sure that www-root has permission.
- I was having trouble with invalid Forms, I was not getting much in the way of an actionable error message. Inserting {{ form.errors }} in the template helping understand the problem.
Result
At this stage, this is sufficient to result in a file getting placed in the assigned directory. I am in the process of designing the E2E user experience through this process, I will follow up with an additional post to cover the next steps.