I'm trying to validate a CSV fileupload by checking all of the expected headers are present. After I pass to validation on my form, the returned file isn't accessible anymore - converting the DictReader object to a list is just now returning an empty list. I'm not receiving any errors.
View:
@login_required
@permission_required('products.report_upload', raise_exception=True)
def uploadPackingNotesView(request):
if request.method == "POST":
form = UploadPackingNotesForm(request.POST, request.FILES)
if form.is_valid():
reader = csv.DictReader(io.StringIO(request.FILES['csv_upload'].read().decode('utf-8')))
packing_list = list(reader)
parsePackingNotes.delay(packing_list)
return HttpResponseRedirect(reverse_lazy('product-csv-upload-successful'))
else:
form = UploadPackingNotesForm()
return render(request, 'products/upload-packing-notes.html', {'form': form})
Form:
class UploadPackingNotesForm(forms.Form):
"""Form used to upload packing notes"""
csv_upload = FileField(label="Select Packing Notes File", validators=[csvPackingNoteValidator])
Validators
def csvPackingNoteValidator(csv_file):
packing_list = csv.DictReader(io.StringIO(csv_file.read().decode('utf-8')))
if not set([
'Branch',
'Carton',
'Delivered',
'SKU',
'PLU',
'Supplier Bar Code',
'Description',
'Size',
'Product Type',
]).issubset(packing_list.fieldnames):
raise ValidationError("Invalid file, select correct report")
Bypassing the form.is_valid() makes it run perfectly, except now I lose validation.
Any ideas? Spent a day and a half trying to troubleshoot and really struggling to find anything on this...?
CodePudding user response:
Issue was that I didnt realise the .read() method does not reset the file pointer (after it had been used in the validation function), so it needed reseting back to 0 prior to the DictReader.
I changed the form.is_valid() block to:
if form.is_valid():
uploaded_csv = form.cleaned_data['csv_upload']
uploaded_csv.file.seek(0)
upload_report = list(csv.DictReader(io.StringIO(request.FILES['csv_upload'].read().decode('utf-8'))))
parseEODReport.delay(upload_report)
return HttpResponseRedirect(reverse_lazy('product-csv-upload-successful'))
The line uploaded_csv.file.seek(0) resets the pointer back to the start.
This post helped me out with this.