1

I am trying to do multiple file uploads in Django but am encountering some errors: form.is_valid() returning false. <br> I have tried printing form.erorrs and it gives me the following:

<ul class="errorlist"><li>uploaded_images<ul class="errorlist"><li>“b&#x27;\xbd\x06D\xcd3\x91\x85,\xdf\xa5K\n&#x27;” is not a valid value.</li></ul></li></ul>

I am not sure how to interpret this general error. Been searching for quite some time but couldn't find an answer.

Edit:
Im also encountering a "This field is required." error
Perhaps this screenshot may help with debugging: enter image description here

I must be missing something simple but I just can't find it!! Another pair of eyes to help me sieve through would be very appreciated!

views.py

from django.shortcuts import render,redirect
from django.views.generic.edit import FormView
from .forms import BRForm
from .models import *

class BRHomeView(FormView):
    form_class = BRForm
    model = TargetImage
    template_name = 'br/br-home.html'
    context_object_name = 'bankrecon'

    def get(self, request):
        form = BRForm(request.POST, request.FILES)
        return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('uploaded_images')
        print("POST")
        print(request.POST)
        print("FILES")
        print(request.FILES)
        print(form.errors)
        if form.is_valid():
            form.save()

        return redirect('br-home')

models.py

from django.db import models

# Create your models here.

class UploadedImages(models.Model):
    image_files = models.ImageField(null=True, blank=True, upload_to='images/')

class TargetImage(models.Model):
    invoice_date = models.DateTimeField()
    recon_date = models.DateTimeField()
    uploaded_images = models.ManyToManyField(UploadedImages)

    def __str__(self):
        return self.invoice_date

forms.py

from django import forms
from django.core.validators import FileExtensionValidator
from .models import *

class BRForm(forms.ModelForm):
    class Meta:
        model = TargetImage
        fields = ('invoice_date', 'recon_date', 'uploaded_images')
        widgets = {
            'invoice_date': forms.DateInput(attrs={'type': 'date'}),
            'recon_date': forms.DateInput(attrs={'type': 'date'}),
            'uploaded_images': forms.ClearableFileInput(attrs={'multiple': True, 'accept':'.jpeg, .png, .jpg'}),
        }

relevant template code:

<div class="mt-5 d-flex justify-content-center">
  <form action="" enctype="multipart/form-data" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <div class="d-flex justify-content-center">
      <button class="btn btn-success mt-3" type="submit">Submit</button>
    </div>
  </form>
</div>

Extra info: My request.POST and request.FILES seems to be working fine:

POST
<QueryDict: {'csrfmiddlewaretoken': ['hiding this'], 'invoice_date': ['2021-02-01'], 'recon_date': ['2021-02-01']}>
FILES
<MultiValueDict: {'uploaded_images': [<InMemoryUploadedFile: first_slide (1).jpg (image/jpeg)>, <InMemoryUploadedFile: fourth_slide (1).jpg (image/jpeg)>]}>

Thank you all!!

Beelz
  • 67
  • 6

2 Answers2

1

Some errors that I see in your code:

  • You're trying to render a POST request in your get method.
  • You're not passing any data from POST request to your form instance. That's why is_valid() is returning False.

Change your code to something like this and see if it works:

...
    def get(self, request):
        form = BRForm()
        return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})

    def post(self, request, *args, **kwargs):
        form = BRForm(request.POST)
        if form.is_valid():
            form.save()

        return redirect('br-home')

phyominh
  • 266
  • 1
  • 7
  • Thank you for pointing out those errors! I see what you mean! Let me try! – Beelz Feb 18 '21 at 11:18
  • I have tried your answer and unfortunately, gave the following when i print: POST FILES , ]}>
    • uploaded_images
      • “b'fN\r'” is not a valid value.
    – Beelz Feb 18 '21 at 11:21
0

I have managed to solve this issue! <br> Link: https://stackoverflow.com/a/60961015/10732211 <br>

I overhauled the entire thing and followed the above link. Probably the models relations have some issues that does not work. <br>

views.py

class BRHomeView(FormView):
    # model = TargetImage
    template_name = 'br/br-home.html'
    context_object_name = 'bankrecon'

    def get(self, request):
        form = BRFormExtended()
        return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})

    def post(self, request, *args, **kwargs):
        form = BRFormExtended(request.POST,request.FILES)
        files = request.FILES.getlist('image_files')

        if form.is_valid():
            print("Form Valid")
            print(form.cleaned_data['invoice_date'])
            print(form.cleaned_data['recon_date'])

            user = request.user
            invoice_date = form.cleaned_data['invoice_date']
            recon_date = form.cleaned_data['recon_date']
            target_image_obj = TargetImage.objects.create(user=user,invoice_date=invoice_date, recon_date=recon_date)
            for file in files:
                UploadedImage.objects.create(target_image=target_image_obj,image_files=file)
        else:
            print("Form Invalid")
        return redirect('br-home')

forms.py

class BRForm(forms.ModelForm):
    class Meta:
        model = TargetImage
        fields = ['invoice_date', 'recon_date']
        widgets = {
            'invoice_date': forms.DateInput(attrs={'type': 'date'}),
            'recon_date': forms.DateInput(attrs={'type': 'date'}),
        }

class BRFormExtended(BRForm):
    image_files = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta(BRForm.Meta):
        fields = BRForm.Meta.fields + ['image_files',]

models.py

from django.contrib.auth.models import User
from django.utils import timezone

class TargetImage(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    uploaded_date = models.DateTimeField(default=timezone.now)
    invoice_date = models.DateTimeField()
    recon_date = models.DateTimeField()

    def __str__(self):
        return self.user.__str__()

class UploadedImage(models.Model):
    target_image = models.ForeignKey(TargetImage, on_delete=models.CASCADE)
    image_files = models.ImageField(null=True, blank=True, upload_to='images/')

Also, it would be helpful to have a media root folder and edits to urls.py is also required.

urls.py

from django.urls import path
from .views import BRHomeView
from django.conf import settings
from django.conf.urls.static import static


urlpatterns = [
    path('', BRHomeView.as_view(), name='br-home'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')


STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)

Hopefully this will help someone!

Beelz
  • 67
  • 6