How can I upload multiple files to a model field?

You have to create a separate model for the files and connect them with a foreign key:

class Feed(models.Model):
    user=models.ForeignKey(User, on_delete=models.CASCADE, related_name='feeds')
    text=models.TextField(blank=False, max_length=500)


class FeedFile(models.Model):
    file = models.FileField(upload_to="files/%Y/%m/%d")
    feed = models.ForeignKey(Feed, on_delete=models.CASCADE, related_name='files')

I hope this helps.


Phew, it took me a whole day to figure out this. My goal was to assign multiple files to one instance of a class, like a Blog instance can have multiple Images. First things first, you cannot do this with one models.FileField inside a model (for example inside Blog class), because this field was not designed to save multiple files. So the solution is to create separate model for the files and connect them with One-to-Many Relationship (Foreign Key) as it was answered by @Carlos Mermingas. Enough words, here is the code for the above situation:

# models.py
class Feed(models.Model):
    user=models.ForeignKey(User, on_delete=models.CASCADE)
    text=models.TextField(blank=False, max_length=500)

class FeedFile(models.Model):
    file = models.FileField(upload_to="files/%Y/%m/%d")
    feed = models.ForeignKey(Feed, on_delete=models.CASCADE)

# forms.py
...
from django.forms import ClearableFileInput
...
class FeedModelForm(forms.ModelForm):
    class Meta:
        model = Feed
        fields = ['text']

class FileModelForm(forms.ModelForm):
    class Meta:
        model = FeedFile
        fields = ['file']
        widgets = {
            'file': ClearableFileInput(attrs={'multiple': True}),
        }
        # widget is important to upload multiple files

# views.py
from .models import FeedFile
...
def create_to_feed(request):
    user = request.user
    if request.method == 'POST':
        form = FeedModelForm(request.POST)
        file_form = FileModelForm(request.POST, request.FILES)
        files = request.FILES.getlist('file') #field name in model
        if form.is_valid() and file_form.is_valid():
            feed_instance = form.save(commit=False)
            feed_instance.user = user
            feed_instance.save()
            for f in files:
                file_instance = FeedFile(file=f, feed=feed_instance)
                file_instance.save()
    else:
        form = FeedModelForm()
        file_form = FileModelForm()

    # the rest is the basic code: template_name, context, render etc. 

# in your template.html <form> tag must include enctype="multipart/form-data"

Bonus: if you want to see uploaded files in admin panel, you can use InlineModelAdmin objects. Here is the code:

# admin.py of your app
from django.contrib import admin
from .models import Feed, FeedFile

class FeedFileInline(admin.TabularInline):
    model = FeedFile


class FeedAdmin(admin.ModelAdmin):
    inlines = [
        FeedFileInline,
    ]

admin.site.register(Feed, FeedAdmin)

For the more details on file upload, Model Forms, how to include widget in Model Form


Would suggest using an M2M field from Feed model to FeedFile model. Makes it all the more easier while querying for files of a particular Feed object, which i feel is also the most common usecase for Feed objects

class Feed(models.Model):
    user=models.ForeignKey(User, on_delete=models.CASCADE, related_name='feeds')
    text=models.TextField(blank=False, max_length=500)
    files=models.ManyToManyField(FeedFile)

class FeedFile(models.Model):
    file = models.FileField(upload_to="files/%Y/%m/%d")

Tags:

Django