I want to upload multiple files through a ModelForm,with all files to be assigned to a file
field of the Model.I have gone through the docs and I saw an example
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")
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