I am using https://github.com/skoczen/django-ajax-uploader to upload a file in django. It works but I would like to rename the uploaded file during the process. I want to add a timestamp so I am sure it has a unique name.
How to do that?
I finally ended up using jQuery-File-Upload. It allows to define the path of the file inside the view.Example:
urls.py
url(r'^upload_question_photo/$', UploadQuestionPhoto.as_view(), name="upload_question_photo"),
index.html
var input=$(this).find("input");
var formData = new FormData();
formData.append('photo', input[0].files[0]);
formData.append('question', input.attr("name"));
formData.append('csrfmiddlewaretoken', '{{ csrf_token }}');
input.fileupload(
{
dataType: 'json',
url: "{% url 'campaigns:upload_question_photo' %}",
formData: formData,
//the file has been successfully uploaded
done: function (e, data)
{
response=data.result;
window.console&&console.log("Successfully uploaded!");
window.console&&console.log(response.path);
}.bind(this),
processfail: function (e, data)
{
window.console&&console.log('Upload has failed');
}.bind(this)
});
views.py
class UploadQuestionPhoto(View):
u"""Uploads photos with ajax
Based on the code #https://github.com/miki725/Django-jQuery-File-Uploader-Integration-demo/blob/master/upload/views.py
"""
def post(self, request, *args, **kwargs):
print "UploadQuestionPhoto post"
response={}
question=str(request.POST["question"])
#path where the file is going to be stored
path="/question/" + question + "/"
photo_path=settings.MEDIA_ROOT + path
# if 'f' query parameter is not specified -> file is being uploaded
if not ("f" in request.GET.keys()):
print "file upload"
# make sure some files have been uploaded
if request.FILES:
# get the uploaded file
photo_file = request.FILES["question_field_" + question]
name_with_timestamp=str(time.time()) + "_" + photo_file.name
# create directory if not exists already
if not os.path.exists(photo_path):
os.makedirs(photo_path)
# add timestamp to the file name to avoid conflicts of files with the same name
filename = os.path.join(photo_path, name_with_timestamp)
# open the file handler with write binary mode
destination = open(filename, "wb+")
# save file data with the chunk method in case the file is too big (save memory)
for chunk in photo_file.chunks():
destination.write(chunk)
destination.close()
#response sent back to ajax once the file has been successfuly uploaded
response['status']='success'
response["path"]=photo_path+name_with_timestamp
# file has to be deleted (TODO: NOT TESTED)
else:
# get the file path by getting it from the query (e.g. '?f=filename.here')
filepath = os.path.join(photo_path, request.GET["f"])
os.remove(filepath)
# generate true json result (if true is not returned, the file will not be removed from the upload queue)
response = True
# return the result data (json)
return HttpResponse(json.dumps(response), content_type="application/json")
VoilĂ ! Hope it helps.
Related
I have a function to submit a file to the server:
function _docs_submit() {
event.preventDefault();
upDOCS_btn.html("Uploading...");
var files = $("#upDOCS").prop('files'),
formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type==='application/pdf') {
continue;
}
formData.append('docs[]', file, file.name);
}
$.ajax({
url: "medcon/adddocs",
type: "POST",
data: formData,
contentType: false,
processData: false,
success: function (locks) {
alert('Thank you.\nDocument(s) received.');
},
error: function(e) {
alert("There was an error submitting your documents:\n" + e.responseText);
}
});
}
How should I capture that in ruby and save to the pdf to the server without using rails and on Ruby 2.4?
post 'medcon/adddocs' do |params|
theFile = params[:data] # need help here
#save file to server - need help here especially
end
I can use gems as long as they match with Ruby 2.4. Thanks.
To access the contents of uploaded file you use file_param[:tmpfile] and you can also access original filename under file_param[:filename] (not sure if you want to reuse it. Armed with that knowledge, you should be able to handle your upload with something like that (not tested, from memory):
post 'medcon/adddocs' do |params|
files = param[:data][:docs] # or maybe string keys, I'm not sure
files.each do |file|
name = file[:filename]
contents = file[:tmpfile].read
File.open(File.join('/some/path', filename), 'wb') { |f| f.write(contents) }
end
end
To access the param values by key, use tic marks. Here's the solution I went with, which includes a method for creating a file directory where it doesn't already exist. To write the file use file.open and wb to write the file in binary mode.
require 'fileutils'
def create_folder(path)
unless File.directory?(path)
FileUtils.mkdir_p(path)
end
end
post 'medcon/adddocs' do |params, me|
params = params['body']
filename = params['data']['filename']
fid = params['fid'].to_s
file = Base64.decode64(params['data']['file_base64'])
folder = "../data/medcon/fid#{fid}"
create_folder folder # send folder path to create folder method
File.open("#{folder}/#{filename}", 'wb') do |f|
f.write(file)
end
end
I am using threading library for a long-running process in Django. When the process is completed, I want to keep updating progress status on the front-end. I am unable to post anything to the ajax.get() from my thread function.
View.py
def upload_handler(request, file_loc, filename):
// do something with uploaded
// I want to notify user that this process is complete via a post
class Uploader(View):
def get(self, request):
file=UploadForm()
return render(request,'template.html',{'form':file}) #,'files':files})
def post(self, request):
file = UploadForm(data=request.POST, files=request.FILES)
if file.is_valid():
x = request.FILES['file']
file.save()
filename = str(request.FILES['file'])
file_loc = os.path.join(BASE_DIR, 'media', 'images', filename)
upload_thread = Thread(target=upload_handler, args=(request, file_loc, filename))
upload_thread.start()
return HttpResponseRedirect(reverse('imageupload'))
urls.py
urlpatterns = [
path('', Uploader.as_view(), name='imageupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
ajax call script
{
$.ajax({
type:"get",
url:"/uploader",
datatype:"json",
success:function(data)
{
console.log(data);
alert("Your file is processed now!");
}
});
}, 1000);
Assume that file uploaded page will remain open till the long process completes.
AJAX option datatype is "json", but the View does not return a "json".
I'm processing a table of banking/statement entries that have been exported from another system via a CSV file. They are imported into a view and checked for duplicates before being presented to the user in a HTML table for final review.
Once checked they are sent via AJAX to the server so they can be added into a Django model. Everything is working OK including CSRF but I cannot access the POSTed variable although I can see it!
Unfortunately making a hidden form isn't viable as there are 80+ rows to process.
My Javascript looks like:
$.ajax({
type: 'POST',
url: '......./ajax/handleImports/',
data: entriesObj,
success: function (data) {
if (data.response && data.response) {
console.log("Update was successful");
console.log(data.entries)
} else { ... }
},
error: function() { ... }
where entriesObj is
var entriesObj = JSON.stringify({ "newentries": newEntries });
console.log(entriesObj)
and when dumped to console.log looks like:
{"newentries":[{"Include":"","Upload ID":"0","Date":"2019-01-09", ... }
Now in view.py when I return the whole request.POST object as data.entries using
context['entries'] = request.POST
return JsonResponse(context)
I get
{"{"newentries":[{"Include":"","Upload ID":"0","Date":"2019-01-09", ... }
but if I try and retrieve newentries with:
entries = request.POST.get('newentries', None)
context['entries'] = entries
return JsonResponse(context)
the console.log(data.entries) will output null?
How am I supposed to access the POSTed entriesObj?
The data is JSON, you need to get the value from request.body and parse it.
data = json.loads(request.body)
entries = data.get('newentries')
After uploading a file in Firebase storage I want to call a firebase cloud function from my web app which will validate the file data I sent to it, and then store it in the real-time database.
I am calling the function using the following code:
var fileRef = 'Files/' + user.uid + '/' + fileId + '/' + file.name;
var storage = firebase.storage().ref(fileRef);
//Upload the file
//..................
// After uploading the file
storage.getMetadata().then(function(metadata) {
var date = metadata.timeCreated.toString();
var storage = firebase.storage().ref('Files/' + user.uid + '/' + fileId + '/' + file.name);
storage.getDownloadURL().then(function(url){
var saveFileData = functions.httpsCallable('saveFileData');
saveFileData({
fileId: fileId,
fileRef: fileRef,
fileData: {
Uploader: user.uid,
Title: title,
FileName: file.name,
Size: fileSize,
DownloadURL: url,
UploadDate: date,
}
}).then(function(){
// Do something
});
});
});
I want to validate values of FileName, Size, DownloadURL and UploadDate in the cloud function based on the following conditions:
fileRef contains an existing file from the firebase storage.
FileName matches with the name of the file represented by fileRef.
Size matches with the size of the file represented by fileRef.
UploadDate matches with the creation date of the file represented by fileRef.
DownloadURL contains the download link of the file represented by fileRef.
What will be an appropriate way to do this from Firebase cloud function?
You can use storage triggers, Deploy in Firebase Cloud Functions,
In the object you will get all the metadata for the uploaded file as like here
exports.generateMetaForUpload = functions.storage
.object()
.onFinalize(object => {
console.log(object);
//do whatever you need to verify
});
I'm using the ajax-upload code to do a simple AJAX file upload. The issue I'm coming across is the file isn't showing up on the backend after submitting.
The frontend code is pretty basic:
<div id="image_uploader">Upload More Images</div>
<script type="text/javascript" charset="utf-8">
function createUploader(){
var uploader = new qq.FileUploader({
element: document.getElementById('image_uploader'),
action: '/add/image/1',
debug: true,
onSubmit : function () {
progress.show();
},
onComplete : function () {
progress.hide();
},
onCancel : function () {
progress.hide();
},
});
};
createUploader();
</script>
The backend code (currently in progress) is also pretty basic:
def add_image(request, id):
print request
if request.FILES:
return HttpResponse("{success:true}")
else:
return HttpResponse("{success:false, message:'Unable to find FILES}")
For me, using code from Alex Kuhl, request.GET['qqfile'] had the filename and request.read() (in Django 1.3) returned the data.
request.FILES was only used in a scenario that hasn't yet happened for me. I'm using ajax-upload to talk directly to Photologue, and my code looks something like this:
def save_upload( uploaded, filename, raw_data ):
"""
raw_data: if True, upfile is a HttpRequest object with raw post data
as the file, rather than a Django UploadedFile from request.FILES
"""
try:
filename = os.path.normpath(os.path.join(IMAGE_UPLOAD_PATH, filename))
with BufferedWriter( FileIO( filename, "wb" ) ) as dest:
# if the "advanced" upload, read directly from the HTTP request
# with the Django 1.3 functionality
if raw_data:
(dirName, fileName) = os.path.split(filename)
(fileBaseName, fileExtension)=os.path.splitext(fileName)
#
# right here, if fileBaseName is less than n characters, might want to slap on a date just for fun
#
try:
i_can_has_p = Photo.objects.get(title=fileBaseName)
title = fileBaseName + "_" + str(datetime.datetime.now().strftime("%Y%m%dT%H%M%S"))
except Photo.DoesNotExist:
title = fileBaseName
title_slug = slugify(title)
p = Photo(title=title, title_slug=title_slug)
p.image.save(filename,ContentFile(uploaded.read()))
# if not raw, it was a form upload so read in the normal Django chunks fashion
else:
# TODO: figure out when this gets called, make it work to save into a Photo like above
for c in uploaded.chunks( ):
dest.write( c )
except IOError:
# could not open the file most likely
return False
return True
def ajax_upload( request ):
if request.method == "POST":
# AJAX Upload will pass the filename in the querystring if it is the "advanced" ajax upload
if request.is_ajax( ):
# the file is stored raw in the request
upload = request
is_raw = True
try:
filename = request.GET[ 'qqfile' ]
except KeyError:
return HttpResponseBadRequest( "AJAX request not valid" )
# not an ajax upload, so it was the "basic" iframe version with submission via form
else:
is_raw = False
if len( request.FILES ) == 1:
# FILES is a dictionary in Django but Ajax Upload gives the uploaded file an
# ID based on a random number, so it cannot be guessed here in the code.
# Rather than editing Ajax Upload to pass the ID in the querystring, note that
# each upload is a separate request so FILES should only have one entry.
# Thus, we can just grab the first (and only) value in the dict.
upload = request.FILES.values( )[ 0 ]
else:
raise Http404( "Bad Upload" )
filename = upload.name
# save the file
success = save_upload( upload, filename, is_raw )
# let Ajax Upload know whether we saved it or not
ret_json = { 'success': success, }
return HttpResponse( json.dumps( ret_json ) )
In my case, ajax_upload is the function called by ajax's action: parameter
Andrew Valums has now got a django app at git hub