form is not accepting image uploads

I am so close to having this all figured out but the form always returns invalid because the image returns None. I imagine it’s something tiny considering as I was typing this I found “image= form.cleaned_date[‘images’]” in the forms.py lol, but that wasn’t the entire problem, it stills returns as None and I just don’t know why. I’ve been through this code with a fine tooth comb.

#views.py
formset_dictionary_copy = request.POST.copy()
            formset = ArtFormSet(formset_dictionary_copy)
            context = {
                'formset': formset,
            }
            if formset.is_valid():
                new_images = []

                for form in formset:
                    title = form.cleaned_data.get('title')
                    images = form.cleaned_data.get('images')
                    short_description = form.cleaned_data.get('short_description')
                    description = form.cleaned_data.get('description')
                    for_sale = form.cleaned_data.get('for_sale')
                    created_on = form.cleaned_data.get('created_on')

                    if title and images and short_description and description and for_sale and created_on:
                        new_images.append(Art(title=title, images=images, short_description=short_description, description=description, for_sale=for_sale, created_on=created_on))

                    try:
                        with transaction.atomic():
                            Art.objects.bulk_create(new_images)

                            messages.success(request, 'Your upload was a success!')

                            context['formset'] = ArtFormSet()
                            return render(request, 'editors/gallery_editor.html', context)
                    except IntegrityError:
                        messages.error(request, 'There was an error uploading your images.')
                        return render(request, 'editors/gallery_editor.html', context)

                context = {
                    'formset': formset,
                    }
                return render(request, 'editors/gallery_editor.html', context)
            else:
                print(formset.errors)
                formset_dictionary_copy = request.POST.copy()
                formset = ArtFormSet(formset_dictionary_copy)
                context = {
                    'formset': formset,
                }
                return render(request, 'editors/gallery_editor.html', context)

#forms.py

from gallery.models import Art

class ArtForm(forms.ModelForm):
    class Meta:
        model = Art
        exclude = ()

class BaseArtFormSet(BaseFormSet):
    def clean(self):
        if any(self.errors):
            return

        titles = []
        images = []
        duplicates = False

        for form in self.forms:
            if form.cleaned_data:
                title = form.cleaned_data['title']
                image = form.cleaned_data['images']

                if title and image:
                    if title in titles:
                        duplicates = True
                    titles.append(title)

                    if image in images:
                        duplicates = True
                    images.append(image)

                if duplicates:
                    raise forms.ValidationError(
                        'You cannot have duplicate titles or images',
                        code = 'duplicates'
                        )
                if image and not title:
                    raise forms.ValidationError(
                        'All images must have a title',
                        code='missing_title'
                    )
                elif title and not image:
                    raise forms.ValidationError(
                        'You need an image to upload',
                        code='missing_image'
                    )

#gallery_editor.html

<main>
            <form method="post" action="" enctype="multipart/form-data">
                {% csrf_token %}
                {{ formset.management_form}}
                {% for form in formset %}
                    <div>{{ form.id }}{{ form }}</div>
                {% endfor %}
                <input type="hidden" value="false" name="additems" id="additems">
                <button class="btn btn-primary" id="additemsbutton">Add items</button>
                <input type="submit" value="Submit order" class="btn btn-primary"> 
            </form>
        </main>

Hi,

When there are file uploads involved, one thing to check is to make sure that you have enctype="multipart/form-data" set on your <form> in your templates (see documentation).

I hope that helps

2 Likes

omg I don’t, I could have sworn I had that but I rewrote that code so many times I must have missed it. facedesk

a heart for catching my oh so obvious mistake, but still None image sigh

edit: I also discovered that I had put images instead of image in the validation error of the form, but that’s not the problem either.

I think the problem is that you’re not passing request.FILES to the formset.

You should instanciate the formset with formset = ArtFormSet(request.POST, request.FILES) (I also don’t understand why you’re copying request.POST, that shouldn’t be necessary)

1 Like

took me a minute to get it right but that was indeed the issue :smiley::smiley: It’s still not uploading the data to the database but I’ll get there. small steps. Thank you for your help

(also just for reference, copying request.POST is how I keep the data in the form when submitting it fails)

Regarding the last point, it’s not necessary. If you want to rerender the form with the previously supplied data, just re-render that form. The form, with data, is persistent through the life of the request.

how do I do that? do you have an example?

Take a look at the example at Working with forms | Django documentation | Django.

Notice how the form being rendered is different depending upon whether it’s a POST or a GET.

1 Like

I think I get it, I’ll work with it later. Thanks again :smiley: