import os, magic, copy from django import forms from .models import Expense, Revenue class CleanInvoiceForm(forms.ModelForm): """ We have to define this form explicitly because we want our ImageField to accept PDF files as well as images, and we cannot change the clean_* methods with an autogenerated form from inside views.py """ invoice = forms.FileField() def clean_invoice(self): # get the uploaded file from cleaned_data uploaded_file = self.cleaned_data['invoice'] # is this a valid image? try: # create an ImageField instance im = forms.ImageField() # now check if the file is a valid image im.to_python(uploaded_file) except forms.ValidationError: # file is not a valid image, so check if it's a pdf # do a deep copy so we dont mess with the file object we might be passing on testfile = copy.deepcopy(uploaded_file) # read the uploaded file into memory (the webserver limits uploads to a reasonable max size so this should be safe) mimetype = magic.from_buffer(testfile.open().read(), mime=True) if mimetype != "application/pdf": raise forms.ValidationError("Only images and PDF files allowed") # this is either a valid image, or has mimetype application/pdf, all good return uploaded_file class ExpenseCreateForm(CleanInvoiceForm): class Meta: model = Expense fields = ['description', 'amount', 'invoice_date', 'invoice', 'paid_by_bornhack', 'responsible_team'] class ExpenseUpdateForm(forms.ModelForm): class Meta: model = Expense fields = ['description', 'amount', 'invoice_date', 'paid_by_bornhack', 'responsible_team'] class RevenueCreateForm(CleanInvoiceForm): class Meta: model = Revenue fields = ['description', 'amount', 'invoice_date', 'invoice', 'responsible_team'] class RevenueUpdateForm(forms.ModelForm): class Meta: model = Revenue fields = ['description', 'amount', 'invoice_date', 'responsible_team']