Post an uploaded file from flask to an API - python

I've build a small flask application with a file input form, and now I want that file to be sent to an API.
#app.route('/test', methods=['POST', 'GET'])
def test():
if request.method == 'POST':
file = request.files['file']
file.save(secure_filename(file.filename))
My Layout for the post part:
data = {
"local": file,
"name": file.filename
}
rp = requests.post(f'https://www.meistertask.com/api/tasks/{task_id}/attachments', data, headers={'Authorization': f'Bearer {access_token}'})
print(rp.status_code)
print(rp.content)
No matter how I try to post that file to the API, I always get this response:
{
"errors": [
{
"message": "Parameter local should be of type ActionDispatch::Http::UploadedFile!",
"status": 400
}
]
}
I really don't know how to post a file of that type from my uploaded file in flask.
I'd really appreciate any help! Thank you very much in advance.

file is not a real file, but a filestorage from the werkzeug package.
https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage
The API documentation of meistertask is not clear to me, especially I cannot see what local should be. A path? A stream? Bytes?

I got it working with python urlib... maybe this helps you
f = open(fname,'rb')
content = f.read()
f.close()
url = 'https://www.meistertask.com/api/tasks/%s/attachments' % (task_id)
request = urllib.request.Request("%s" %(url))
boundary = "5645645645654"
request.add_header("User-Agent", "python-test")
request.add_header("Accept", "*/*")
request.add_header("Accept-Encoding", "gzip, deflate")
request.add_header("Content-Type","multipart/form-data; boundary=%s" % boundary)
request.add_header("Connection", "keep-alive")
request.add_header("Expect", "100-continue")
request.add_header("Authorization", "Bearer 11111111111111111111")
body = bytes("--%s\r\n" % boundary,'utf-8')
body += bytes('Content-Disposition: form-data; name="name"\r\n\r\n','utf-8')
body += bytes('%s\r\n' % fname,'utf-8')
body += bytes("--%s\r\n" % boundary,'utf-8')
body += bytes('Content-Disposition: file; name="local"; filename="%s"\r\n' % fname,'utf-8')
body += bytes('Content-Type: text/plain\r\n\r\n','utf-8')
body += content
body += bytes('\r\n','utf-8')
body += bytes("\r\n--%s--\r\n" % boundary,'utf-8')
request.data = body
#print(body)
f = urllib.request.urlopen(request)
response = f.read() #bytes

Related

How to do a good callback function with django rest framework

I would like to write an api with django rest framework, I got some issues with my callback function.
I can get the access code, but how to give it to my app?
This is my callback function :
#api_view(['GET'])
def callback(request):
if request.method == 'GET':
code = request.GET.get("code")
encoded_credentials = base64.b64encode(envi.SECRET_ID.encode() + b':' + envi.SECRET_PASS.encode()).decode("utf-8")
token_headers = {
"Authorization": "Basic " + encoded_credentials,
"Content-Type": "application/x-www-form-urlencoded"
}
token_data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": "http://127.0.0.1:800/callback"
}
test = "test :" + code
return JsonResponse(test, safe=False)
And this is my view where I try to do some stuff (I use spotify's API, with spotipy), I need to get the users name or mail :
#api_view(['GET'])
#permission_classes([permissions.IsAuthenticated])
def test(request):
if request.method == 'GET':
test = "test " + request.user.username
scope = "user-read-private"
sp = getScope(scope)
print(sp.current_user())
urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=envi.SECRET_ID, client_secret=envi.SECRET_PASS, redirect_uri=envi.SPOTIPY_REDIRECT_URI))
artist = sp.artist(urn)
print(artist)
user = sp.current_user()
return JsonResponse(user, safe=False)
def getScope(spotipyScope):
token = SpotifyOAuth(scope=spotipyScope,client_id=envi.SECRET_ID, client_secret=envi.SECRET_PASS, redirect_uri=envi.SPOTIPY_REDIRECT_URI)
spotifyObject = spotipy.Spotify(auth_manager= token)
return spotifyObject
When I do a get on 127.0.0.1:8000/test/, I have a new page on my browser, from spotify, I connect my account, and then, it redirects me on 127.0.0.1:8000/callback/?code=some_code
How can I give it to my first page waiting for the code so I can print the users stuff pls?

Sending image from flutter to flask

When I try to send image from flutter to flask, flask shows error 400.
I have no idea where is an error in my flutter code. Flutter function gets file(image in my case) as Uint8List. Then, I cast it as List, and trying to send with multipart.
Here is the code from flask and flutter.
Flask:
#auth.post('update/avatar')
#jwt_required()
def update_avatar():
current_user = get_jwt_identity()
save_folder = 'images/users/'
file = request.files.get('file', None)
file.filename = str(current_user) +".jpeg"
filename = secure_filename(file.filename)
file.save(os.path.join(save_folder, filename))
Flutter:
Future<String> uploadAvatar(Uint8List file, int userId) async {
var url = ApiConstants.baseUrlAuth + ApiConstants.updateAvatar + userId.toString();
String? access = await storage.storage.read(key: 'access');
if(access == null){
return '';
}
http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse(url));
List<int> _selectedFile = file;
request.headers.addAll({'Authorization': access, "Content-type": "multipart/form-data"});
request.files.add(http.MultipartFile.fromBytes('file', _selectedFile, contentType: MediaType('file', 'jpeg'),));
http.StreamedResponse response = await request.send();
final responseStr = await response.stream.bytesToString();
Map data = json.decode(responseStr);
if (response.statusCode == 401 && data.containsKey("msg") && data['msg'] == "Token has expired!"){
String res = auths.refreshToken() as String;
if(res == "success"){
res = uploadImagePost(file, userId) as String;
}
return res;
} else if(response.statusCode == 201){
return data['photo_url'];
}
return '';
}
}
According to http Error 400 (Bad Request) the error is because request was somehow corrupted on the way.
check this Mozilla docs for more information about the main error.

request post with python's requests package does not work

I am working with the django framework. I'm trying to send a post request with token using the requests package but it doesn't work. the status code of the request is 200.Here is my code:
def modifier_periode_push(request):
url = "ip_addr/openapi/device"
option1,option2,option3 = "040A0001","041E0001","043C0001"
headers = {
"Accept-Encoding":"gzip","Content-Length":"286","Content-Type":"application/json","Token":"xxxxxxxxx",
"User-Agent":"python-requests/2.26.0"
}
if request.is_ajax() and request.method == "POST":
if request.POST["periode"] == "10":
payload = convertir_en_hexa(option1)
elif request.POST["periode"] == "30":
payload = convertir_en_hexa(option2)
else:
payload = convertir_en_hexa(option3)
data = {
"devEUI":request.POST["devEUI"],
"confirmed":False,
"fPort":int(request.POST["fPort"]),
"data":payload
}
try:
**req = requests.post(url, headers=headers, data=data)**
print(req.status_code)# returns 200
except:
print("Erreur")
return HttpResponse("ok")
else:
return HttpResponse("Requete non authorisée")
I have got this message {'code': 1003, 'msg': 'No Token, Please log in again'}
I want to know why it does not work and how to debug.

Auto download not working for Django FileResponse

I need to let the Django auto download the generated file.
Tried all different solutions online, none of them works.
Views.py
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
response = FileResponse(open(zip_filepath, 'rb'), as_attachment=True)
return response
raise Http404
Template: code for the form POST.
$(document).on('submit', '#productForm', function(e){
e.preventDefault();
var inputFilePath = document.getElementById('sourceFileInput').files.item(0).name;
$.ajax({
method: 'POST',
url: 'validate/',
data: {
source_file: inputFilePath,
region: $("#Region-choice").val(),
product_type: $("#Product-type").val()}
})
.done(function(){
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
document.getElementById('lblStatusContent').innerHTML = "Success!"
})
.fail(function(req, textStatus, errorThrown) {
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
alert("Something went wrong!:" + textStatus + ' ' + errorThrown )
});
});
});
It's not possible to download files to your computer via an ajax (XHR) request. So you need to redirect the user actually (setting window.location) to a view that downloads the file. Or you can add as a result of the successful POST a button the current page so the user can download the file. In any case, you need to move the file download to a different view so a standard GET request can fetch it.
But your code to return the file in Django (using FileResponse) is correct.
There's also an explanation with an alternative way of doing it here
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
with open(zip_filepath, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(zip_filepath)
return response
raise Http404

Django return file as string, not as a file

I try to put statistics in excel spreadsheets in dynamic way, so when
excel.js
$('.js-excel').on('click', function () {
$.get(
'/ajax/stat_excel/',
{
'excel': 'loan',
'date_from': $('#date_from').val(),
'date_to': $('#date_to').val()
}
)
})
then
view.py
output = StringIO.StringIO()
workbook = xlsxwriter.Workbook(output)
if request.GET.get('excel') == 'loan':
workbook = loanChart.excel(workbook)
if request.GET.get('excel') == 'debet':
workbook = debetChart.excel(workbook)
workbook.close()
xlsx_data = output.getvalue()
response = HttpResponse(xlsx_data, mimetype='application/vnd.ms-excel')
response['Content-Type'] = 'application/vnd.ms-excel'
response['Content-Disposition'] = 'attachment; filename=report.xlsx'
return response
And I'm not sure what I'm doing wrong, because response be like
PK�������F��AS]$��w������xl/worksheets/sheet1.xml��[oɑ���W|W+#�>�dx(�{}�%j$�$
$������ʞ��8�]C�.��QU���������//�q�����ۛ:�����?|���77��y�n^<=�}�p�������������y����O���,���
Excel file generates excellent. I can see it, if I don't use StringIO
I'm not sure, what I need to use, Mimetype or Content-Type. Can't see any difference. Works exactly the same, no matter which type I write in response.
Where can be my problem?
Found answer here https://stackoverflow.com/a/4518775/4498908.
I can't use ajax for file download. But I can:
function download(path,val) {
window.location.href = path+"download.php?val="+val;
};

Categories

Resources