Search code examples
djangoformsdjango-formsdjango-viewsdjango-uploads

Multiple images in django form with multiupload


I need to add multiple images in django form to one model. I did a research and for form outside of django I try to setup django-multiupload.

My models.py:

class Profile(models.Model):
    ...
    ...
    first = models.ImageField("first", upload_to='first')
    second = models.ImageField("second", upload_to='second')
    ...

In forms.py:

class AddForm(forms.ModelForm):
    first = MultiImageField(min_num=1, max_num=20)
    second = MultiImageField(min_num=1, max_num=4)

In views.py:

class UploadView(FormView):
    template_name = 'finder/submit.html'
    form_class = AddForm
    success_url = '/'

    def form_valid(self, form):
        for each in form.cleaned_data['first']:
            Profile.objects.create(first=each)
        for each in form.cleaned_data['second']:
            Profile.objects.create(second=each)
        return super(UploadView, self).form_valid(form)

And on submitting form this form creates multiple Profile objects with only first/second field filled.

How can I create only one model with remaining fields (other than first/second) and with multiple first/second fields?

It was my function-based view before adding multiupload but I couldn't make it work, maybe it's easier to change it somehow?

def add_form(request, *args, **kwargs):
    if request.method == "POST":
        form = AddForm(request.POST)
        if form.is_valid():
            profile = form.save(commit=False)
            profile.save()
            return redirect('/', pk=profile.pk)
    else:
        form = AddForm()
    return render(request, 'finder/submit.html', {'form': form})

Solution

  • I have never used the Django-multiupload, but I happen to read some of the docs.

    If you want to save multiple files for your user model, you may need to create another model for accommodating the files and add a Foreign Key towards the Profile model. Remove the first and second fields from Profile model. It causes you to create multiple profiles with same data inorder to accomodate multiple images.

    Simple example,

    class Image(models.Model):
        image = models.FileField()
        profile = models.ForeignKey(Profile, related_name='images')
        is_first = models.BooleanField(default=False)
        is_second = models.BooleanField(default=False)
    

    Then, edit the save method in form,

    class AddForm(forms.ModelForm):
        first = MultiImageField(min_num=1, max_num=20)
        second = MultiImageField(min_num=1, max_num=4)
    
        class Meta:
            model = Profile
            fields = (.......... 'first', 'second')
    
        def save(self, commit=True):
            first_images = self.cleaned_data.pop('first')
            second_images = self.cleaned_data.pop('second')
            instance = super(AddForm, self).save()
            for each in first_images:
               first = Image(image=each, profile=instance, is_first=True)
               first.save()
    
            for each in second_images:
               second = Image(image=each, profile=instance, is_second=True)
               second.save()
    
            return instance
    

    Then, on the views, edit the view,

    class UploadView(FormView):
        template_name = 'finder/submit.html' 
        form_class = AddForm 
        success_url = '/' 
    
        def form_valid(self, form): 
            instance = form.save(commit=False)
            instance.user = self.request.user
            instance.save()
    
            return super(UploadView, self).form_valid(form)
    

    Or in function based view,

    def add_form(request, *args, **kwargs): 
        if request.method == "POST": 
            form = AddForm(request.POST)
            if form.is_valid(): 
                profile = form.save(commit=False) 
                profile.user = request.user
                profile.save() 
                return redirect('/', pk=profile.pk) 
        else: 
            form = AddForm() 
        return render(request, 'finder/submit.html', {'form': form})