xlsx file not being exported django rest framework - python

I am calling ajax request from frontend to export data in excel sheet.
js
function exportData(){
create_spinner("Please wait while we export data.");
var agent = $("#agent").val()
var dateRange = $("#dateRangeValue").val()
var queue = $("#queue").val()
var direction = $("#direction").val()
var department = $("#department").val()
var serviceLevel = $("#sl").val()
$.ajax({
type: 'POST',
url: "/call-record-api/export-data/",
data: {
"agent": agent,
"dateRange": dateRange,
"queue": queue,
"direction": direction,
"department": department,
"serviceLevel": serviceLevel,
},
success: function(resultData) {
console.log("success");
hide_spinner();
},
error: function (err) {
console.log("AJAX error in request: " + JSON.stringify(err, null, 2));
create_spinner("Couldn't export data. Please try again");
setTimeout(function(){ hide_spinner()}, 1000);
}
});
}
I have gone through documentation and implemented the same.
urls.py
url(r'^call-record-api/export-data/$', ExportCallRecordView.as_view({"post":"list"})),
views.py
class ExportCallRecordView(XLSXFileMixin, ReadOnlyModelViewSet):
def get_queryset(self):
calls = export_customized_calls(self.request)
print(calls.count())
return calls
serializer_class = CallRecordSerializer
renderer_classes = [XLSXRenderer]
filename = 'call_record_export.xlsx'
But i cannot see the file getting downloaded. However i can see success in browser console and 235 as call count in server console.

You can't download files directly with ajax. You have to use tricks like this (taken from a github repo):
// jQuery ajax
$.ajax({
type: "POST",
url: url,
data: params,
success: function(response, status, xhr) {
// check for a filename
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = new Blob([response], { type: type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
});
Or if you don't mind converting your POST request in to GET request:
window.location = `/<download_url>/?param1=${encodeURIComponent(param1)}`

Related

Send file path from flask to Ajax

I'm trying to send a file path to my Ajax script which reads file contents and displays it on the page
#app.route('/main', methods=['GET'])
def main():
filename = '/static/js/'+current_user.username+'log.txt'
return render_template('main.html',name=current_user.username,data=filename)
js script
var checkInterval = 1; //seconds
var fileServer = '{{ data }}';
var lastData;
function checkFile() {
$.get(fileServer, function (data) {
if (lastData !== data) {
$( "#target" ).val( data );
$( "#target" ).animate({
scrollTop: $( "#target" )[0].scrollHeight - $( "#target" ).height()
}, 'slow');
lastData = data;
}
});
}
$(document).ready(function () {
setInterval(checkFile, 1000 * checkInterval);
});
I tried different ways to do this, changed fileServer to 'data.filename'/{{ data| json }} etc but got no luck.
How can I do this?
If you pass the entire url generated with url_for as a parameter it should work.
#app.route('/main', methods=['GET'])
def main():
filename = url_for('static', filename=f'js/{current_user.username}log.txt')
return render_template('main.html', name=current_user.username, data=filename)
As a supplement, I also specify that the request should not be stored in the cache.
const checkInterval = 1;
const fileServer = "{{ data }}";
let lastData;
function checkFile() {
$.get({ url: fileServer, cache: false }, function(data) {
if (lastData !== data) {
$("#target").val(data);
$("#target").animate({
scrollTop: $("#target")[0].scrollHeight - $("#target").height()
}, "slow");
lastData = data;
}
});
}
$(document).ready(function() {
setInterval(checkFile, 1000 * checkInterval);
});
I used jquery version 3 for testing.

400 bad Request using axios, flask and react

I am unable to make post request via react js to python-flask server.
I am using axios. This request works on postman, but I can't seem to figure out why I can make post request from my react app.
Please see flask code:
#app.route('/match_home_types', methods=['GET', 'POST'])
def match_home_types():
area = request.form['area']
response = jsonify({
'home_types': util.match_area_with_types(area)
})
response.headers.add('Access-Control-Allow-Origin', '*')
return response
My react-redux action code:
export const matchHouseTypes = (area) => (dispatch) => {
axios
.post("http://127.0.0.1:5000/match_home_types", area)
.then((res) => {
dispatch({
type: MATCH_TYPES,
payload: res.data.home_types,
});
})
.catch((error) => {
console.log(error.response);
});
};
my react class component:
get_house_types = () => {
const { selectedOption } = this.state;
if (selectedOption == "Find a location") {
alert("Please select a valid location");
}
var area = {
area: selectedOption.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase()),
};
console.log("area:", area);
this.props.matchHouseTypes(area);
};
See below error response from axios:
data: "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">↵<title>400 Bad Request</title>↵<h1>Bad Request</h1>↵<p>The browser (or proxy) sent a request that this server could not understand.</p>↵"
status: 400
statusText: "Bad Request"
Please assist
The issue was that I was not sending the API parameters the right way. Since I am sending via form data I changed my code from:
var area = {
area: selectedOption.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase()),
};
to:
const formData = new FormData();
formData.append(
"area",
selectedOption.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase())
);
complete function:
get_house_types = (e) => {
e.preventDefault();
const { selectedOption } = this.state;
if (selectedOption == "Find a location") {
alert("Please select a valid location");
} else {
const formData = new FormData();
formData.append(
"area",
selectedOption.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase())
);
this.props.matchHouseTypes(formData);
}
};

How to redirect and pass data in angular js with post method

I want to redirect and pass some data to other page.But not using query string and not pass data in URL
(function() {
var app = angular.module('PlateformApp', [])
app.controller('PlateformController', function ($scope,$window) {
//This will hide the DIV by default.
$scope.IsVisible = false;
$scope.ShowHide = function (platform) {
//If DIV is visible it will be hidden and vice versa.
$scope.IsVisible = $scope.IsVisible ? true : true;
//alert(platform);
document.getElementById("platform").value = platform;
var myEl = angular.element( document.querySelector( '#plat_val' ) );
myEl.text(platform);
}
$scope.storeAppWindow = function()
{
//store_url = $scope.storeUrl;
test_bc_url = ""
text_sh_url = ""
platform_val = document.getElementById("platform").value;
$http.get("/user/installedapp")
.then(function(response) {
$scope.myWelcome = response.data;
});
if (platform_val == "BC")
$window.open(test_bc_url, "popup", "width=500,height=400,left=10,top=50");
else if (platform_val == "Sh")
$window.open(text_sh_url, "popup", "width=500,height=400,left=10,top=50");
}
});
})();
Here It will open new window but i want to pass platform_val text_sh_url url in another page.And i am using flask in python.
You can pass the data by various methods, using $stateParams,using Storages, using factories or services. You can find the example using storage in my answer in this thread: sharing data using storages
(function() {
var app = angular.module('PlateformApp', [])
app.factory('newService', function() {
function set(data) {
datatosend = data;
}
function get() {
return datatosend;
}
return {
set: set,
get: get
}
});
app.controller('PlateformController', function($scope, $window, newService) {
//This will hide the DIV by default.
$scope.IsVisible = false;
$scope.ShowHide = function(platform) {
//If DIV is visible it will be hidden and vice versa.
$scope.IsVisible = $scope.IsVisible ? true : true;
//alert(platform);
document.getElementById("platform").value = platform;
var myEl = angular.element(document.querySelector('#plat_val'));
myEl.text(platform);
}
$scope.storeAppWindow = function()
{
//store_url = $scope.storeUrl;
test_bc_url = ""
text_sh_url = ""
platform_val = document.getElementById("platform").value;
$http.get("/user/installedapp")
.then(function(response) {
$scope.myWelcome = response.data;
});
if (platform_val == "BC") {
$window.open(test_bc_url, "popup", "width=500,height=400,left=10,top=50");
}
else if (platform_val == "Sh") {
var data = {
'platform_val': platform_val,
'text_sh_url ': text_sh_url
};
newService.set(data);
$window.open(text_sh_url, "popup", "width=500,height=400,left=10,top=50");
}
}
});
})();
And,in the page where you want to get the data. Just inject newService in the controller of that page and use newService.get(data)
app.controller('pageController',function($scope,newService){
var datafromanothercontroller = newService.get(data);
console.log(datafromanothercontroller );
})

XMLHttpRequest for sending files is not sending the data to the server

I want to upload files from a angularjs 2 app to my python server application.
the formData look perfect before sending it to the server. Containing name and file data.
On the other end is a Python API waiting to accept the file data. But i don't get the data. Debugger PDB get activated as the send is done by angularjs 2 app but i am missing the file data.
What could i be doing wrong?
upload.service.ts
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
#Injectable()
export class UploadService {
constructor(private http: Http) { }
uploader(files: any) {
let xhr = new XMLHttpRequest();
const formData = new FormData();
for(var i = 0; i < files.length; i++){
formData.append(files[i].name, files[i]);
}
var headers = new Headers();
headers.append('Content-Type', 'multipart/form-data');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response))
} else {
reject(xhr.response)
}
}
}
xhr.open('POST','http://192.168.1.205:5000/zino', true)
xhr.send(formData)
}
}
python flask API debugger
As you see, the request.values are empty :(
<Request 'http://192.168.1.205:5000/zino' [POST]>
(Pdb) request.values
CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([])])
This is a working example for RC angular2
import {Injectable} from '#angular/core';
import {Http, Headers, RequestOptions} from '#angular/http';
#Injectable()
export class UploadService {
constructor(private http: Http) { }
uploader(files: any) {
let xhr = new XMLHttpRequest()
const formData = new FormData()
for(var i = 0; i < files.length; i++){
formData.append(files[i].name, files[i])
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
//resolve(JSON.parse(xhr.response))
} else {
//reject(xhr.response)
}
}
}
xhr.open('POST','/server/upload-api', true)
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
xhr.send(formData)
}
}
On the python side you find the files in
(Pdb) req.httprequest.files
ImmutableDict({'IMGP0269.jpg': <FileStorage: u'IMGP0269.jpg' ('image/jpeg')>, 'IMGP0270.jpg': <FileStorage: u'IMGP0270.jpg' ('image/jpeg')>})

Flask not interacting with Ajax

This script
<script type="text/javascript">
$(function() {
$('.send').live('click', 'button', function()
{
var user1 = $(this).val();
var user2=$(this).prev().val();
var text=$(this).prev().prev().val();
var my_data = {
user1: user1, text:text, user2:user2,
};
console.log(my_data)
$.ajax({
url: "/updatechat",
data: my_data,
type: 'POST',
success: function(response) {
console.log(response)
},
error: function(error) {
console.log(error);
}
});
});
});
is raising an error with the correspondent route /updatechat
#app.route('/updatechat', methods=['GET','POST'])
def updatechat():
user1 = request.form['user1']
user2 = request.form['user2']
text = request.form['text']
return [user1,user2,text] #not the actual code
but will NOT raise the same error if, in the previous piece of code, i replace with this
user1='bbb'
user2='whatever'
text='idk'
this "var = request.form['var']" form works on several different routes on my code
Solved
The proper form was user1 = request.values.get("user1")
source: https://stackoverflow.com/a/20341272

Categories