Django uploading/downloading multiple files - django

Using Django 2.0
What i'm trying to do is post a link for each file uploaded. But my problem is that when I upload multiple files, the field only takes the last one.
So long I have tried this:
In my CBV
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('Resource_file')
if form.is_valid():
for f in files:
f.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
in my forms.py
Resource_file = forms.FileField(
widget=forms.FileInput(attrs= {
"multiple": True,
}
),
required = False
)
for example 6 files were uploaded and saved on my media root yet only one is related with the field...
How can I save multiple files and display each one on my template?
Extra: How can I verify the file extension when displaying them on my template? I would like to make like an icon for each type of file.

Related

For loop on form not functing properly

I have a feature that allows users to upload multiple images to their blog but it is not working correctly. When a user uploads multiple images only one of them is uploaded to the postgres db.
view
def DetailPostView(request, pk):
model = Post
post = Post.objects.get(pk=pk)
if request.method == 'POST':
test = PostImagesForm(request.POST, request.FILES)
files = request.FILES.getlist('images')
if test.is_valid():
for f in files:
instance = test.save(commit=False)
instance.post = Post.objects.get(pk=pk)
instance.save()
else:
print(instance.errors)
postgallery = PostImages.objects.filter(post_id=post)
context = {
'post':post, 'PostImagesForm':PostImagesForm, 'postgallery':postgallery
}
return render(request, 'blog/post_detail.html', context)
form
class PostImagesForm(ModelForm):
class Meta:
model = PostImages
fields = ('images',)
widgets = {
'images': forms.ClearableFileInput(attrs={'multiple': True}),
}
you can see i am getting the list of files via the files = request.FILES.getlist('images') then running a for loop on the contents.
If I break the code in the stack trace I can see that the two files are in the list so i am very confused on why it is not properly iterating though the list and uploading each file to the db.
Update
Took a look into the docs and found a section on multi image upload and the docs are doing it the same way I am. Still very confused.
I believe the issue was the because I was not passing the current image into the model so it only uploaded the first image.
Solution
if request.method == 'POST':
for f in request.FILES.getlist('images'):
test = PostImagesForm(request.POST, request.FILES)
if test.is_valid():
instance = test.save(commit=False)
instance.post = Post.objects.get(pk=pk)
instance.images = f
instance.save()

Save multiple files using FileField

In a existing form I use a FileField to attach differents type of files .txt, .pdf, .png, .jpg, etc and work fine but now I need that field to accept several files, so I use the propertie multiple for the input to accept more of one files but when is stored in my database only stored the path for the first selected file and in the media folder are only stored one file no the others, this is what I have:
forms.py
class MyForm(forms.Form):
attachment = forms.FileField(required=False,widget=forms.ClearableFileInput(attrs={'multiple': True}))
models.py
class MyFormModel(models.Model):
attachment = models.FileField(upload_to='path/', blank=True)
Is posible to store in the DB all the paths separete in this way path/file1.txt,path/file2.jpg,path/file3.pdf and store the three files in the media folder? Do I need a custom FileField to procces this or the view is where I need to handle this?
EDIT: The answer #harmaahylje gives me comes in the docs but not for the versiĆ³n I use 1.8 this affect the solution?
Do something like this in the forms.py:
class FileFieldForm(forms.Form):
attachment = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Django docs have the solution https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#uploading-multiple-files
In your view:
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)

How can i process a multiple files from a file field in django?

I am trying to figure out how to process multiple files from a filefield in Django. I have figured out how to add the "multiple" attribute to the form field. What I need to do now is loop through each file and perform some logic.
I have a form with fields like this (in views.py):
class RecipientListForm(forms.Form):
name = forms.CharField()
recipients = forms.CharField(
required=False,
widget=forms.Textarea(attrs={'placeholder':"James Jameson, james.jameson#aol.com"}),
label="Paste recipient information (comma-separated, in 'name, email' format)")
recipients_file = RecipientsFileField(
required=False,
widget=forms.FileInput(attrs={'multiple':"true"}),
label="Or upload a .csv file in 'name, email' format (max size %dMB)" % RecipientsFileField.MAX_FILESIZE_MB)
def __init__(self, account, recipient_list=None, *args, **kwargs):
super(RecipientListForm, self).__init__(*args, **kwargs)
self.account = account
self.recipient_list = recipient_list
def clean(self, *args, **kwargs):
...
RecipientsFileField looks like this (also in views.py):
class RecipientsFileField(forms.FileField):
MAX_FILESIZE_MB = 30
def validate(self, value):
super(RecipientsFileField, self).validate(value)
if not value: return
fname = value.name
if (value.content_type not in (('text/csv',) + EXCEL_MIMETYPES) or not re.search(r'\.(xlsx?|csv)$', fname, re.I)):
raise forms.ValidationError('Please upload a .csv or .xlsx file')
if value.size >= self.MAX_FILESIZE_MB * 1024 * 1024:
raise forms.ValidationError('File must be less than %dMB' % (self.MAX_FILESIZE_MB,))
I have tried to perform my logic in the clean method of RecipientListForm but I have only been able to access the first file that is uploaded, it seems that the other files are not uploaded. I have looked at the docs but the way these forms are setup don't seem to be reflected in the documentation about forms, unless I am just looking in the wrong place. Thanks in advance!
According to this section of the Django docs, you should be able to get the files from the request object with:
files = request.FILES.getlist('recipients_file')
Hope this helps.

How to upload files in Django and save them in a different location depending on the format? (jpeg and doc)

How to upload files in Django and save them (and take other actions in the signal - post_save) in a different location depending on the format? (jpeg and doc)
def upload(request):
user = request.user
upload_form = UploadForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if upload_form.is_valid():
my_model = upload_form.save(commit=False)
my_model.user = user
my_model.save()
models:
class FileStore(models.Model):
user = models.ForeignKey(User)
standard = models.FileField(upload_to="standard")
after_operation = models.FileField(upload_to="after_ocr",blank=True, null=True)
signal:
#receiver(post_save, sender=FileStore)
def my_handler(sender,instance, **kwargs):
if kwargs['created']:
text= image_to_string(Image.open(instance.standard))
...
instance.after_operation = File(text_file)
instance.save()
I want if file is .doc or .pdf save only in standard field and if file is .jpeg or .png I need run my signal function.
For instance, you can retrieve the uploaded file by accessing the request.FILES dictionary like this:
uploaded_file = request.FILES['file']
uploaded_file is now of type UploadedFile which means you can get info about the file like this:
# name of the file, ie: my_file.txt
filename = uploaded_file.name
# file extension (get the las 4 chars)
file_ext = filename[-4:]
# handle file extension
if file_ext == '.jpg':
# do something for jpegs
if file_ext == '.doc':
# do something for docs
So now, for saving it you may try this, I haven't prove it yet:
# f is the UploadedFile
model_file = File(f)
model_file.save('path/to/wherever.ext', f.readlines(), true)
I hope this helps! This may not work out of the box but I hope it bring some light to the problem. Try to look at the docs: django files and django uploaded files. This topic is very well documented.
Good luck!

Binding Files to Form Django Wizard

So I was unsuccessful at hooking up the Session-based wizard from django-merlin, but I am trying again with the wizard that is included in the django source. However, when trying to upload files using ImageField, it seems that the files request.FILES are not being bound to the form, because after trying to upload a file I get a "This Field is Required" error. Here is what I have:
forms.py:
class StepOneForm(forms.Form):
year = forms.ChoiceField(choices=YEAR_CHOICES)
...
class StepTwoForm(forms.Form):
main_image = forms.ImageField()
...
class CreateWizard(SessionWizardView):
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT))
def done(self, form_list, **kwargs):
d['main_image'] = request.FILES['main_image']
db = Thing(**d)
db.save()
return render(request, 'wizard-done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
In the CreateWizard above I have tried to save the main_image in the done method as was discussed in this stackoverflow question, but I have not been successful.
UPDATE:
Adding enctype=multipart/form-data has allowed me to bind the file, but now I am getting a new error:
global name 'request' is not defined
even though the request context processor is in my TEMPLATE_CONTEXT_PROCESSORS. Defining the done method like in the linked stackoverflow post did not work either:
class CreateWizard(SessionWizardView):
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT))
def done(self, request, form_list):
results in a TypeError: done expects 3 arguments, 2 given
You will need self.request:
return render(self.request, 'wizard-done.html', {
'form_data': [form.cleaned_data for form in form_list], })