How to upload multiple images from a single "Choose Files" selector in django admin
Asked Answered
C

2

7

I'm doing this little project simulating a clothing ordering system to brush up my django skills.

I have to add several pictures of a certain item(not a fixed number). So, using a fixed number of image fields in Item model is not ideal. So, I thought of another model consisting only of images connected to the model 'items' by a key.

Now I know that django has the inline option for adding model objects one by one as per requirement. But that seems a bit of a sucker as you have to open that dialog box and select the images one by one.

Is it possible that there be a selector via which we could choose multiple files at once and they be added to the model??

Churchyard answered 14/4, 2018 at 1:52 Comment(3)
github.com/Chive/django-multiuploadMetatarsal
Here is your right answer-https://mcmap.net/q/347756/-how-to-upload-multiple-images-to-a-blog-post-in-djangoSystematic
Maybe this answer could also help.Distichous
A
10

Yes, there is a handy way. First declare an image class, something like:

class Image(models.Model):
    condo = models.ForeignKey(Condo, on_delete=models.CASCADE, related_name='images')
    image = models.FileField(upload_to="images/")
    uploaded_at = models.DateTimeField(auto_now_add=True)

In the form creation don't add a line for presenting a FileField

class ListingForm(forms.ModelForm):
    ...
    ...
    #photos = forms.FileField(required=False) #Don't do it.

But rather in the template, among the other lines, add this too:

<form action="" method="post" autocomplete="off" enctype="multipart/form-data">
    {% csrf_token %}
    {{ your_form|crispy }} <br/>
    <input type="file" name="images" multiple>
    <input type="submit" value="Submit">
</form>

In the view that handles your POST request, you can process the uploaded images with:

from app.forms import Image


if request.method == 'POST':
...
...
    for file in request.FILES.getlist('images'):
        instance = Image(
            condo=Condo.objects.get(your_parent_objects_id),
            image=file
        )
        instance.save()

This creates new Image object for each image and saves the actual files to your media folder.

Additionally, I'd suggest to rename the files your users are uploading due to possible malicious acts.

I've done this by creating a small function and using it instead of the "images/" part for it.

import uuid
def images_directory_path(instance, filename):
    return '/'.join(['images', str(instance.condo_id.id), str(uuid.uuid4().hex + ".png")])

# in Image class (models.py)
image = models.FileField(upload_to=images_directory_path)

This last modification generates new names for the images as uuid4, adds .png extension to them and creates full link to the media/ folder.

enter image description here

Of course, there is no validation present whether the format or size of the uploaded files are valid, but that is a topic for another question.

You can access the images with the variable images as it is the related_name for all connected images to the given object (in this case Condo).

Lastly, this is a a great article by Vitor Freitas about using Javascript plugins for uploading multiple images with progress bar.

Amido answered 14/4, 2018 at 20:50 Comment(0)
M
4

from the docs (https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/):

Uploading multiple files If you want to upload multiple files using one form field, set the multiple HTML attribute of field’s widget:

forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': 
True}))

Then override the post method of your FormView subclass to handle multiple file uploads:

views.py

from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldView(FormView):
    form_class = FileFieldForm
    template_name = 'upload.html'  # Replace with your template.
    success_url = '...'  # Replace with your URL or reverse().

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for f in files:
                instance = Image(image=file)  # match the model.
                instance.save()
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

and add a model:

from django.db import models

class Image(models.Model):
    image = models.FileField(upload_to='images/%Y/%m/%d')
    uploaded_at = models.DateTimeField(auto_now_add=True)

and add to urls.py urlpatterns:

path(‘upload/’,views.FileFieldView.as_view(),name=‘FileFieldView’),
Meander answered 27/11, 2019 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.