Django file upload get data and store in database - django

I am new to Django and would like to seek advise regarding file uploads. The user can upload multiple files, but I do not wish to store the files in the database. I just want to get the data from the files and store the data in the database. Is there a way to do it? Is storing the files locally the way to do it?
I have seen ways to temporarily store the files locally (but I have seen examples where we need to specify our own (computer) path which may be different for different computers). Is there a way to specify a path where any computers can store the files locally?
Apologies that there is no code as I am still thinking how am I going to do it.

Most people would say just store the file paths in the database and have the web server serve the files. Unless you want people to upload something like a spreadsheet, then you should use a spreadsheet plugin to get the contents into lists and dictionaries which you can write out as models.
Heres how to do it the way you requested:
def handle_uploaded_file(upload):
contents = file.read() # Add .decode('ascii') if Python 3
my_model = MyModel(some_other_field='something')
my_model.field = contents
my_model.save()
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})

Related

Can i upload files in one django filefield as a list of files?

I have created a webpage where a candidate can apply for jobs. There, they can list different previous experiences. I am handling all experience details by concatenating them in my models and splitting them while fetching. how should I handle files in such a case?
My Applicant model has the FileField called company_doc. Can it also somehow take multiple files so that I can retrieve them via some indexing? is that possible?
There is, at the moment of writing, no FileField for a model that can store multiple files. Usually this is modelled with an extra model, for example CompanyDoc that has a FileField and a ForeignKey to the Applicant model, so:
class Applicant(models.Model):
# …
pass
class CompanyDoc(models.Model):
applicant = models.ForeignKey(
Applicant, on_delete=models.CASCADE
)
file = models.FileField(upload_to='company_doc/')
You can then construct a form that can upload multiple files with:
from django import forms
class CompanyDocsForm(forms.Form):
files = forms.FileField(
widget=forms.ClearableFileInput(attrs={'multiple': True})
)
and then process this with:
def some_view(request, applicant_id):
if request.method == 'POST':
form = CompanyDocForm(request.POST, request.FILES)
if form.is_valid():
data = [
CompanyDoc(file=file, applicant_id=applicant_id)
for file in request.FILES.getlist('files')
]
CompanyDoc.objects.bulk_create(data)
else:
# …
pass
else:
# …
pass
# …
For more information, see the Uploading multiple files section of the documentation.

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 to serialise request.POST to a database and back again

I'm trying to implement a simple "checkpointing" system to save partially completed formsets. I've got a set of large forms (say 100 entries) for a data-entry project. Now, if the person quits or whatever, halfway through, then I'd like this progress saved - but I don't want the half-entered data saved in the database until it's complete.
As far as I can see the best way to deal with this is to save request.POST to a database field and pull it out again e.g.
def myview(request, obj_id):
obj = get_object_or_404(Task, obj_id)
if request.POST:
# save checkpoint
obj.checkpoint = serializers.serialize("json", request.POST)
else:
# load last version from database.
request.POST = serializers.deserialize("json", obj.checkpoint)
formset = MyFormSet(request.POST)
# etc.
But, this gives me the following error:
'unicode' object has no attribute '_meta'
I've tried simple json and pickle and get the same errors. Is there any way around this?
Django's serializer interface works with django model objects. It will not work with other objects.
You may try to use json
if request.POST:
# save checkpoint
obj.checkpoint = json.dumps(request.POST)
post_data = request.POST
else:
# load last version from database.
post_data = json.loads(obj.checkpoint)
formset = MyFormSet(post_data)

Django: Upload a file and read its content to populate a model?

I am new to Django and would like to know what is the Django-way to add elements in a database not by entering each field from an html form (like it is done by default) but uploading a single file (for example a json file) that will be used to populate the database?
So let say the model has only three fields: title,description,quantity.
And I have a text file (myFile.txt) with "myTitle:myDesc" written in it.
What I want is just a FileField that will accept a text file so I can upload myFile.txt and the title and description will be read from this file.
And at the same time the quantity will be asked "normally" in a text input as it would be by default (only title and description are read from the file).
Of course, validation on the file will be done to accept/deny the uploaded file.
The problem I am facing is that if I add a FileField to the model, the file will be stored in the local storage.
I want the content of the uploaded file to be read, used to create an entry in the model, and then deleted.
Even the admin should not be able to manually add an element entering the title and description in a HTML form but only by uploading a file.
Can someone help me in a Django-way?
You can create two forms:
A form based on django.forms.Form which is used to get the file from request
A model form which is used to validate model fields and create a model object
Then you can call the second form from the first one, like this:
class MyModelForm(ModelForm):
class Meta:
model = MyModel
class FileUploadForm(forms.Form):
file = forms.FileField()
def clean_file(self):
data = self.cleaned_data["file"]
# read and parse the file, create a Python dictionary `data_dict` from it
form = MyModelForm(data_dict)
if form.is_valid():
# we don't want to put the object to the database on this step
self.instance = form.save(commit=False)
else:
# You can use more specific error message here
raise forms.ValidationError(u"The file contains invalid data.")
return data
def save(self):
# We are not overriding the `save` method here because `form.Form` does not have it.
# We just add it for convenience.
instance = getattr(self, "instance", None)
if instance:
instance.save()
return instance
def my_view(request):
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
else:
# display errors
You can use form wizard to achieve such tasks. The basic idea is to create two forms; one with the FileField and the other form with the title, description quantity fields.
The user views the form with FileField first. Once the user uploads the file and submits the request, you can render the other form with initial values read from the file (you can also delete the file at this step).
Regarding the admin functionality, you can read about how to integrate form wizard with admin here
I found another way of populating a model before saving it.
Instead of using pre_save, or using 2 different forms, if we are using the admin.ModelAdmin, we can simply redefine the save_model() method:
def save_model(self, request, obj, form, change):
obj.user = request.user
# populate the model
obj.save()
# post actions if needed
To achieve this you have to write some custom code. Each FileField has a connected File object. You can read the content of this file object like you would when dealing with files in Python.
There are of course different locations you could do that. You can overwrite the forms/models save method which contains the FileField. If you have model you could use pre_save/post_save signals as well.

Django ModelForm Ajax Upload

I'm using an Ajax code for uploading files. Django takes good care of file uploads on ModelForms. Just writing form.save() would upload any file data in the header, manage creating the folders if needed and even rename the file if a duplicate already exists. Take this ModelForm which only has one filed named file for example:
class UploadFileForm(ModelForm):
class Meta:
model = MyModel
fields = ('file',)
Since I'm using Ajax the only information I have in my view is request.FILES['file']. This is what I tried in my view:
form = UploadFileForm(initial={'file':request.FILES['file']})
if form.is_valid():
form.save()
But it returns an invalid form (file is required). I can do this using pure Python but with the power of Django where's the point in that?
form = UploadFileForm(request.FILES)
if form.is_valid():
form.save()
initial parameter let you initialize form fields, like giving a new form filed some initial data.
Here, you are getting the file data from a request.