A long time ago, I wrote a blog post and some code that validates file uploads in Django. In the last week, it seems a lot of people have been interested in the post and since Django finally has a stable 1.0 release, I thought I would update the previous blog post.
Custom field, with validation
First, here is the new code for a Django form field that validates the filename and content type of an uploaded file. This example makes sure that the file is a Word, OpenOffice, text, HTML or PDF document:
# v_fields.py
from django import forms
from django.utils.translation import gettext as _
class DocumentValidationError(forms.ValidationError):
def __init__(self):
super(DocumentValidationError, self).__init__(_(u'Document types accepted: ') + ', '.join(DocumentField.valid_file_extensions))
class DocumentField(forms.FileField):
"""A validating document upload field"""
valid_content_types = ('text/html', 'text/plain', 'text/rtf',
'text/xml', 'application/msword',
'application/rtf', 'application/pdf')
valid_file_extensions = ('odt', 'pdf', 'doc', 'txt',
'html', 'rtf', 'htm', 'xhtml')
def __init__(self, *args, **kwargs):
super(DocumentField, self).__init__(*args, **kwargs)
def clean(self, data, initial=None):
f = super(DocumentField, self).clean(data, initial)
ext = splitext(f.name)[1][1:].lower()
if ext in DocumentField.valid_file_extensions \
and data['content-type'] in DocumentField.valid_content_types:
return f
raise DocumentValidationError()
Warning, this is only the form field. Second, You will have to do some extra wiring to be able to display it. Before I show you how to hook it up, we need a sample model. The following is a Document model that has a title, a content_type and a document field:
# models.py
from django.db import models
from django.utils.translation import gettext as _
class Document(models.Model):
content_type = models.CharField(max_length=5, blank=True, null=True)
document = models.FileField(upload_to='documents/%Y/')
title = models.CharField(_(u'Title'), max_length=80)
Custom form
I'm using a FileField for the document field. Next, we have the wiring for a form:
# v_forms.py
from models import Document
from django.forms import ModelForm
from v_fields import DocumentField
class DocumentForm(ModelForm):
document = DocumentField()
class Meta:
model = Document
fields = ('title', 'document')
Whenever a form is created for the Document model, the document field will be a DocumentField object. This is the field that has the validation method as shown above.
Custom admin form
Third, lovely Django finally allows us to create and use custom forms with the admin module and so I wrote a bit of code that hooks into the above form.
# admin.py
from django.contrib import admin
from django_sample.documents.models import Document
from v_forms import DocumentForm
class DocumentAdmin(admin.ModelAdmin):
form = DocumentForm
admin.site.register(Document, DocumentAdmin)
More information
You can look up more information on each component:
Leave some feedback! Does it work for you? How could I improve it?
