Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django formset creates multiple inputs for multiple image upload

Tags:

python

django

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")
like image 709
doğukan Avatar asked Mar 31 '20 22:03

doğukan


2 Answers

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>
like image 117
shoytov Avatar answered Oct 29 '22 22:10

shoytov


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.

like image 23
Dhruv Agarwal Avatar answered Oct 29 '22 23:10

Dhruv Agarwal