3

Class below is used to create a form in Django and get neccesary information. Problem is, it offers only one file to upload. I need to upload multiple files. I use Crispy forms.

My simplified view.py looks like:

class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'file_1']

    def form_valid(self, form):   
        form.instance.author = self.request.user

        return super().form_valid(form)

HTML code:

{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
    <div class="content-section">

        <form method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Fill form</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Submit</button>
            </div>
        </form>
    </div>
{% endblock content %}

When I inspect page, object looks like:

<input type="file" name="file_1" class="clearablefileinput form-control-file" id="id_file_1">

I want it to contain multiple atribute. How can I achive that? I can't get it to work using documentation (https://docs.djangoproject.com/en/3.2/topics/http/file-uploads/).

I have tried:

widgets = {'file_1': form.ClearableFileInput(attrs={'multiple': True})}

form.instance.file_1 = form.FileField(widget=form.ClearableFileInput(attrs={'multiple':True}))

form.instance.file_1 = form.FileField(widget=form.FileInput(attrs={'multiple': True}))

My models.py

file_1 = models.FileField(blank=True, upload_to='PN_files/%Y/%m/%d/', verbose_name="File 1", validators=[validate_file_size], help_text="Allowed size is 50MB")

I can't find an example how to implement multiple files upload which could be implemented in my class.

UPDATE! (thanks to 'amadou sow') I've updated my class to:

class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'file_1']

    def form_valid(self, form):   
        form.instance.author = self.request.user
        
        obj = form.save(commit=False)
        if self.request.FILES:
            for f in self.request.FILES.getlist('file_1'):
                obj = self.model.objects.create(file=f)

        return super().form_valid(form)

And I've added script to my HTML page to add atribute of MULTIPLE:

    <script>
      $(document).ready(function(){
        $('#id_file_1').attr("multiple","true");

      })
    </script>

Now I get an option to select multiple files and upload them, but when I do that, only 1 file is stored in my media folder.

MarkoZg
  • 391
  • 2
  • 10

1 Answers1

7

To answer your question i will try to create a foreign key to the post and i will use function views

app/models.py:

class Post(models.Model):
    #add your all other fields here execept (files)
class File(models.Model):
     post = models.ForeignKey(Post,on_delete=models.CASCADE)
     file = models.FileField(blank=True, upload_to='PN_files/%Y/%m/%d/', verbose_name="Files", validators=[validate_file_size], help_text="Allowed size is 50MB")

app/forms.py:

from .models import Post,File
class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = [#the field that you want to rendered]
class PostFileForm(PostForm): #extending form
    file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta(PostForm.Meta):
        fields = PostForm.Meta.fields + ['file',]

app/views.py:

from .forms import PostFileForm
from .models import File

def postcreate(request):
    if request.method == 'POST':
        form=PostFileForm(request.POST or None,request.FILES or None)
        files = request.FILES.getlist('file')
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            #add everything you want to add here
            post.save()
            if files:#check if user has uploaded some files
                for f in files:
                    File.objects.create(post=post,file=f)
             
            return redirect('the-name-of-the-view')
    else:
        form = PostFileForm()
    return render(request,'the-template-you-want-to-rendered-',{'form':form})

with this you can upload many files you want.and if you don't want the file to be required you can add "required=False" inside the PostFileForm.

Thierno Amadou Sow
  • 2,523
  • 2
  • 5
  • 19
  • Hello I followed the method the the form is not submitting. where did I do the mistake! I am unable to figure out that – Anny Mar 30 '22 at 06:08
  • @Anny could you please ask an other question and send me the link i can't tell you what you are doing wrong if i do not see your code. – Thierno Amadou Sow Mar 30 '22 at 08:19
  • thanks a lot for your response. here is my question link https://stackoverflow.com/q/71674131/12499225 – Anny Mar 30 '22 at 08:46