Django + Axios: File download not working in Firefox - django

I am using Axios to send my Django backend information, which in turns creates a file and sends it back to the front end. The code I have below works great in Safari and Chrome. However, the file does not download in firefox. BTW, no errors show up in the firefox console, or in Django.
Axios
axios({
method:'post',
url:'/api/downloadDoc',
responseType:'blob',
data: params,
})
.then(response => {
let blob = new Blob([response.data], {type: 'application/force-download'})
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = "YourPaper.docx"
link.click()
})
.catch(e => {
console.log(e)
})
Django View Sending File
def downloadPaper(request):
if request.method == "POST":
#Recieve info through post and create document
#variable path is path to newly created document
wrapper = FileWrapper(open(path, 'rb'))
response = HttpResponse(wrapper, content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename=' + 'yourpaper.docx'
response['Content-Length'] = os.path.getsize(path)
return response
return HttpResponse(status=405)
I am hoping someone knows what could be causing firefox to not download.
Thanks!

fetch("/api/admin/plugin/download/" + id , {
method: 'GET',
headers: new Headers({
"Authorization": this.token,
"Allow-Control-Allow-Origin": "*",
"Content-Type" : "application/octet-stream"
}),
}).then(response => {
response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement('a');
// must add <a> to body, then it works
document.body.appendChild(a);
a.style.display = 'none';
a.href = url;
a.download = decodeURI(response.headers.get("filename"));
a.click();
document.body.removeChild(a);
});
})

Related

Downloading a file via Axios from Django

I'm trying to get filename from blob request using Axios and Django.
Django's view:
with open(full_file_path, 'rb') as f:
response = HttpResponse(f, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
file_expr = "filename*=utf-8''{}".format(quote(file_name_with_ext))
response['Content-Disposition'] = 'attachment; {}'.format(file_expr)
return response
Frontend:
axios
.request({
url,
method,
responseType: 'blob',
})
.then(({ data }) => {
console.log(data);
const downloadUrl = window.URL.createObjectURL(new Blob([data]));
const link = document.createElement('a');
link.href = downloadUrl;
link.setAttribute('download', 'file.xlsx');
document.body.appendChild(link);
link.click();
link.remove();
});
But parameter 'data' doesn't contain headers to allow me to get filename.
Is there any solution?
instead of this .then(({ data }) => { Use this:.then(response =>{
and response.data is your data from response that you can see with console.log(response.data);
Hope it helps<3.

Not able to connect to the translation API

url: https://translatorappeagle.cognitiveservices.azure.com/
I'm also using my key from my resources page. I get a an error 404: not found. I copied the code from the getting started section for the translation API.
Please let me know what to do.
import os, requests, uuid, json
key_var_name = 'TRANSLATOR_TEXT_SUBSCRIPTION_KEY'
if not key_var_name in os.environ:
raise Exception('Please set/export the environment variable: {}'.format(key_var_name))
subscription_key = os.environ[key_var_name]
endpoint_var_name = 'TRANSLATOR_TEXT_ENDPOINT'
if not endpoint_var_name in os.environ:
raise Exception('Please set/export the environment variable: {}'.format(endpoint_var_name))
endpoint = os.environ[endpoint_var_name]
# If you encounter any issues with the base_url or path, make sure
# that you are using the latest endpoint: https://learn.microsoft.com/azure/cognitive-services/translator/reference/v3-0-translate
path = '/translate?api-version=3.0'
params = '&to=de&to=it'
constructed_url = endpoint + path + params
headers = {
'Ocp-Apim-Subscription-Key': subscription_key,
'Content-type': 'application/json',
'X-ClientTraceId': str(uuid.uuid4())
}
# You can pass more than one object in body.
body = [{
'text' : 'Hello World!'
}]
request = requests.post(constructed_url, headers=headers, json=body)
response = request.json()
print(json.dumps(response, sort_keys=True, indent=4, separators=(',', ': ')))

Cookies works in Postman , but not in browser

I created a login API using Django rest framework and then used session auth.
When i sent request via Postman , i get csrftoken and sessionid cookies.
and i was able to access content on backend.
OK fine.
But when i built small login form html and called that API for logging in. It worked.
I see COOKIES IN RESPONSE BUT COOKIES ARE NOT SET IN CHROME BROWSER.
Under Storage section in dev tools cookies are empty.
when i tried to access content(other views/apis) , i was not able to..
I think its because of Cookies are not being stored in browser..
Been on this like 5 days. Please can Someone explain about cookies not being saved.?
View.py
class Login(APIView):
authentication_classes = [SessionAuthentication,]
def post(self, request, format=None):
username = request.POST.get("username", "")
print(request.session)
password = request.POST.get("password", "")
user = authenticate(request,username=username,password=password)
if user is not None:
login(request,user)
print(user)
return Response('Yes')
else :
return Response('No')
class List(APIView):
authentication_classes = [SessionAuthentication,]
permission_classes = [IsAuthenticated,]
def get(self, request, format=None):
return Response("Ark")
My Axios Request for login :
let s = this;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
myHeaders.append("Authorization", "Basic cjox");
myHeaders.append("Access-Control-Allow-Credentials","*");
var urlencoded = new URLSearchParams();
var requestOptions = {
method: 'POST',
credentials: 'same-origin',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
axios.post("http://127.0.0.1:8000/api/login/",urlencoded,{headers:myHeaders},{withCredentials: true})
.then(res=>{
console.log(res.headers);
})
My other request :
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
myHeaders.append("Access-Control-Allow-Credentials","*");
var urlencoded = new URLSearchParams();
var requestOptions = {
method: 'GET',
credentials: 'same-origin',
headers: myHeaders,
redirect: 'follow'
};
axios.get("http://127.0.0.1:8000/api/d/",{headers:myHeaders},{withCredentials: true});

ionic 2 upload image to django rest

I am trying to upload an image from Ionic 2 app to Django-powered website through Django Rest API.
The API is working and tested through Postman but I always get HTTP 400 BAD Request error in Ionic.
Here is my code in Ionic:
openCamera(){
var options = {
sourceType: Camera.PictureSourceType.CAMERA,
destinationType: Camera.DestinationType.DATA_URL
};
Camera.getPicture(options).then((imageData) => {
this.imageName = imageData;
this.imageURL = 'data:image/jpeg;base64,' + imageData;
}, (err) => {
this.showAlert(err);
});
}
Upload file (I am serving my Django project on my local PC with IP address 192.168.22.4):
transferData(auth){
let headers = new Headers();
headers.append('Authorization', auth);
let formData = new FormData();
formData.append('image', this.imageURL, this.imageName);
this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
let status = res['status'];
if(status == 200){
this.showAlert( "The image was successfully uploaded!");
}else{
this.showAlert("upload error");
}
}, (err) => {
var message = "Error in uploading file " + err
this.showAlert(message);
});
}
On Django, here is my serializer:
class ImageDetailsSerializer(serializers.ModelSerializer):
image = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user') ####status, category has default value
and views.py:
class ImageDetailsViewSet(generics.ListCreateAPIView):
queryset = ImageDetails.objects.all()
serializer_class = ImageDetailsSerializer
I am not sure if my code in uploading file is correct. I am trying to pass the data through Form data since the form works well in my API. Is this method correct? Are there any other methods to get this work?
Note: I have tried to use Transfer Cordova plugin but it is not working.
I finally solved the problem. The HTTP 400 indicates that there is a syntax error somewhere in the code and that is the encoding used in the uploaded photo. Mobile data uses base64 encoding. When sending requests, the file will then be converted to a Unicode string.
On the other hand, Django-Rest uses normal encoding for images, thus by default, it cannot support base64 image. But luckily, this plugin is already available at GitHub.
You just need to install the plugin and import it on your serializers.py:
from drf_extra_fields.fields import Base64ImageField
class ImageDetailsSerializer(serializers.ModelSerializer):
image = Base64ImageField()
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user')
On Ionic side, you have to submit the actual image not the imageURL. In my case I just have to tweak my code to:
transferData(auth){
let headers = new Headers();
headers.append('Authorization', auth);
let formData = new FormData();
formData.append('category', 1);
formData.append('status', 'Y')
formData.append('image', this.imageName);
this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
let status = res['status'];
if(status == 201){
var message = "The image was successfully uploaded!";
this.showAlert(message);
}else{
var message = "upload error";
this.showAlert(message);
}
}, (err) => {
var message = "Error in uploading file " + err;
this.showAlert(message);
});
In order to inspect what's ongoing with the request:
from rest_framework.exceptions import ValidationError
class ImageDetailsViewSet(generics.ListCreateAPIView):
queryset = ImageDetails.objects.all()
serializer_class = ImageDetailsSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if not serializer.is_valid():
print(serializer.errors) # or better use logging if it's configured
raise ValidationError(serialize.errors)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Even without Base64 it is possible using ionic native components for file-transfer and image-picker see here: https://gist.github.com/AndreasDickow/9d5fcd2c608b4726d16dda37cc880a7b

Anonymus user Django + Angular 2

i am using django + angular 2
i am using rest_framework_jwt with a url like this
url(r'^api/api-token-auth/', obtain_jwt_token),
url(r'^api/settings/?$', views.SettingsValues.as_view()),
My view is
class SettingsValues(generics.ListAPIView):
serializer_class = SettingsSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self):
queryset = Settings.objects.all()
queryset = queryset.filter(user=self.request.user.id)
print self.request.user
return queryset
My service is:
getSettings() : Promise <SettingsValues> {
return this.http.get('/api/settings', { headers: this.headers })
.toPromise()
.then(response => response.json() as SettingsValues);
}
My login is working fine, but i cannot return the settings from django..
The print inside def get_queryset shows AnonymousUser.
Any idea what i am doing wrong ?
EDIT
private headers = new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json',
});
After obtaining the token from server, you have to save it and send in the header of subsequent api calls. Something like this:
getSettings() : Promise <SettingsValues> {
this.headers.append('Authorization', 'JWT ' + token);
return this.http.get('/api/settings', { headers: this.headers })
.toPromise()
.then(response => response.json() as SettingsValues);
}
In Angular 1.x.x, i can add this to cache Authorization Header for all subsequent api calls.
$http.defaults.headers.common.Authorization = 'JWT ' + token`;
In Angular 2, I am not sure how to cache it for all but take a look at this answer