John
John

Reputation: 2922

How to handle multi-file input field in Django

I have a database that tracks items.

Each item can have multiple images associated with it.

My models look like this:

class Item(models.Model):
    name = ...
    price = ...
    description = ...

class ItemImage(models.Model):
    item = models.ForeignKey("Item", on_delete=models.CASCADE, related_name="images")

Before trying to add the images field to each item, my views looked like this:

class ItemAdd(CreateView):
    model = Item
    fields = ['name', 'price', 'description']
    ...

class ItemEdit(UpdateView):
    model = Item
    fields = ['name', 'price', 'description']
    ...

In order to add an images field, I changed my views to say this:

class ItemAdd(CreateView):
    model = Item
    form_class = ItemEditForm
    ...

class ItemEdit(UpdateView):
    model = Item
    form_class = ItemEditForm
    ...

And created this form:

class ItemEditForm(forms.ModelForm):
    images = forms.ImageField(required=False, widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta:
        model = Item
        fields = ('name', 'price', 'description')

This adds the file input field to my templates, but doesn't actually do anything with the images the user chooses.

Django's documentation has some info on how to handle multiple file uploads here, which is where I got the above images field code, but the sample code doesn't appear to be aware of models at all. If the form being edited is in the CreateView, and the Item doesn't exist yet, I could create the ItemImage object in the post() code, but I have no Item to associate it with.

I must be missing something, because it seems like this should be relatively simple.

Upvotes: 0

Views: 317

Answers (1)

Oleg Russkin
Oleg Russkin

Reputation: 4404

As sample code at the referenced link suggested: ...Then override the post method of your FormView... - you need to add saving logic for images in your view.

For Class-Based CreateView this is done in form_valid():

class ItemAdd(CreateView):
    model = Item
    form_class = ItemEditForm
    ...

    def form_valid(self, form):
        self.object = form.save() # create Item first
        images = self.request.FILES.getlist('images')
        for image in images:
            self.object.images.create(image=image)
        return HttpResponseRedirect(self.get_success_url())

For UpdateView you may need a bit different saving logic for images. And probably a preview of already present images.

Nice API-Doc on Class-Based Views

Upvotes: 1

Related Questions