doğukan
doğukan

Reputation: 27531

Django formset creates multiple inputs for multiple image upload

I am trying to create a simple post sharing form like this one.

enter image description here

I'm using formset for image upload. But this gives me multiple input as you can see. Also each input can choose single image. But I'm trying to upload multiple image with single input.

views.py

def share(request):

    ImageFormSet = modelformset_factory(Images,
                                        form=ImageForm, extra=3)
    # 'extra' means the number of photos that you can upload   ^

    if request.method == 'POST':
        postForm = PostForm(request.POST)
        formset = ImageFormSet(request.POST, request.FILES,
                               queryset=Images.objects.none())

        if postForm.is_valid() and formset.is_valid():
            post = postForm.save(commit=False)
            post.author = request.user
            post.save()

            for form in formset.cleaned_data:
                # this helps to not crash if the user
                # do not upload all the photos
                if form:
                    image = form['image']
                    photo = Images(post=post, image=image)
                    photo.save()

            return redirect("index")

        else:
            print(postForm.errors, formset.errors)
    else:
        postForm = PostForm()
        formset = ImageFormSet(queryset=Images.objects.none())
    return render(request, "share.html", {"postForm": postForm, 'formset': formset})

share.html

 <form  method="POST" id="post-form" class="post-form js-post-form" enctype="multipart/form-data">
            {% csrf_token %}
             {{ formset.management_form }}
                {% for form in formset %}
                    {{ form }}
                {% endfor %} 
   </form>

if you need, forms.py

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ["title", "content"]

    def __init__(self, *args, **kwargs):
        super(PostForm, self).__init__(*args, **kwargs)
        self.fields['title'].widget.attrs.update({'class': 'input'})
        self.fields['content'].widget.attrs.update({'class': 'textarea'})


class ImageForm(forms.ModelForm):
    image = forms.ImageField(label='Image')

    class Meta:
        model = Images
        fields = ('image', )

        def __init__(self, *args, **kwargs):
            self.fields['image'].widget.attrs.update(
                {'class': 'fileinput', 'multiple': True})

models.py

from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify


class Post(models.Model):
    # on_delete ile, bu kullanıcı silindiğinde bu kullanıcıya ait tüm postlar da silinecek.
    author = models.ForeignKey(
        "auth.User", on_delete=models.CASCADE, verbose_name="Yazar")
    title = models.CharField(max_length=150, verbose_name="Başlık")
    content = models.TextField(verbose_name="İçerik")
    # auto_now_add = True ile veritabanına eklendiği tarihi otomatik alacak
    created_date = models.DateTimeField(auto_now_add=True)

    # admin panelinde Post Object 1 yazması yerine başlığı yazsın istersek...
    def __str__(self):
        return self.title


def get_image_filename(instance, filename):
    title = instance.post.title
    slug = slugify(title)
    return "post_images/%s-%s" % (slug, filename)


class Images(models.Model):
    post = models.ForeignKey(
        Post, on_delete=models.DO_NOTHING, default=None)
    image = models.ImageField(upload_to=get_image_filename,
                              verbose_name='Image', default="images/default_game_img.png")

Upvotes: 7

Views: 1344

Answers (2)

Dhruv Agarwal
Dhruv Agarwal

Reputation: 558

I think you are over thinking the implementation you should try lib like django-multiupload

And can find valid implementation for multiple image upload through this link

https://stackoverflow.com/a/44075555/10798048

Hope this will ease your implementation and solve your problem. Correct me if it doesn't work out for you.

Upvotes: 2

shoytov
shoytov

Reputation: 605

If you need one filed for multiple image upload, try this:

views.py

from .forms import PostForm
from .models import Post, Images

def share(request):
    form = PostForm()

    if request.method == 'POST':
        post = Post()
        post.title = request.POST['title']
        post.content = request.POST['content']
        post.author = request.user
        post.save()

        for image in request.FILES.getlist('images'):
            image_obj = Image()
            image_obj.post_id = post.id
            image_obj.image = image
            image_obj.save()

    return render(request, 'share.html', {'form': form})

forms.py

from django import forms

class PostForm(forms.Form):
    title = forms.CharField(label='', 
                        widget=forms.TextInput(attrs={
                            'class': 'input',
                            }
                        )) 

    content = forms.CharField(label='', 
                           widget=forms.Textarea(attrs={
                               'class': 'textarea',
                               }
                           ))                    

    images = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

share.html

<form  method="POST" id="post-form" class="post-form js-post-form" enctype="multipart/form-data">
            {% csrf_token %}
            {% for elem in form %}
                {{ elem }}
            {% endfor %}
</form>

Upvotes: 8

Related Questions