Django throwing 500 error when reading POST data - python

I am sending a POST request to my server which is throwing a 500 error when my server code attempts to read data from the POST request. But the data looks perfectly ok to me.
The POST data is:
<QueryDict: {u'{"firstname":"jack","lastname":"rowley","username":"jack","email":"info#mybiz.co.uk","password":"jack","city":"London","country":"UK","photo":"","genre1":"Comedy","genre2":"Horror","genre3":"Documentary","platform":"Cinema"}': [u'']}>
The Python code that is reading the POST data is:
username = request.POST['username']
password = request.POST['password']
email = request.POST['email']
It falls over at the first line, trying to access the username.
The AngularJS code that makes the POST request looks like this:
url = apiDomain + '/profile/register/';
var fn = 'jack';
var ln = 'rowley';
var un = 'jack';
var pw = 'jack';
var cf = 'jack';
var em = 'info#mybiz.co.uk';
var lc = 'London';
var ct = 'UK';
var ph = ''; //$('#photo_set').val();
var genre1 = 'Comedy';
var genre2 = 'Horror';
var genre3 = 'Documentary';
var platform = 'Cinema';
return $http({
method: 'POST',
url: url,
headers: {
'Content-Type': "application/x-www-form-urlencoded"
},
data: {
firstname: fn,
lastname: ln,
username: un,
email: em,
password: pw,
city: lc,
country: ct,
photo: ph,
genre1: genre1,
genre2: genre2,
genre3: genre3,
platform: platform
}
}).then(function successCallback(response) {
return response;
}, function errorCallback(response) {
return -1;
});

You are trying to access this data as if it were form-encoded. It is not; it is JSON.
You need to access the raw post body, and decode it from JSON.
data = json.loads(request.body)
username = data['username']
password = data['password']
email = data['email']

You're getting a KeyError because you don't have a username.
Your query dict is not a dict. It's a single-item string key, with an empty-string value. The key happens to be a string-encoding of some url encoding string. Look at it.
QueryDict: { u'{"fi text text text': u'' }
You are passing a URL-encoded string where you should be passing a dict, probably in the client.

Related

How to specify arguments for a Python api using Kotlin?

I made a python api that I'm trying to get my app to connect to, but for the login function I need to send the username and password but I'm not sure how to do this. This is the python code:
username = data.get('username')
email = data.get('email')
password = data.get('password')
And the Kotlin Code:
private fun sendData(username:String, password:String): Thread {
return Thread {
val url = URL("https://127.0.0.1:5000/login")
val connection = url.openConnection() as HttpsURLConnection
connection.setRequestProperty("username", username)
connection.setRequestProperty("password", password)
if (connection.responseCode == 200) {
val inputSystem = connection.inputStream
println(inputSystem.toString())
Toast.makeText(applicationContext, "It worked", Toast.LENGTH_SHORT).show()
}
else {
var code: String = "ERROR"
Toast.makeText(applicationContext, "NO CONNECTION", Toast.LENGTH_SHORT).show()
}
}
}
The connection is opened but I can get any data across and I haven't tried anything so far as I can't find good documentation on this.
You could, for example, first set up a class to handle your credentials:
class LoginData(
val userID: String,
val pw: String
){
/** Returns a hashmap of the data stored in the class object. */
fun getHashmap(): Map<String,String> {
val params = HashMap<String,String>()
params["username"] = userID
params["password"] = pw
return params
}
/** Obtains a JSONObject of the data stored in the class object. */
fun getJson(): JSONObject {
val params = this.getHashmap()
return JSONObject(params)
}
}
And then, utilising Volley (don't forget to add it to your build gradle: implementation 'com.android.volley:volley:1.2.0'), do something like this:
fun sendData(username: String?, password: String?) {
val url = "https://127.0.0.1:5000/login"
var loginData = LoginData(
userID = username!!,
pw = password!!
)
val queue = Volley.newRequestQueue(this)
val jsonRequest = JsonObjectRequest(
Request.Method.POST,
url,
loginData.getJson(),
Response.Listener {
response -> handleResponse(response)//do something with the response
},
Response.ErrorListener { error -> println("That didn't work: $error")})
queue.add(jsonRequest)
}
with handleResponse() containing your logic to evaluate what comes back from the server:
fun handleResponse(response: JSONObject) {
//your evaluation logic
}

Python Dynamics 365 package to read write data

We managed to connect to our dynamics 365 cloud instance with token auth. However, we were hoping to find package like "pydynamics".
The package "https://libraries.io/pypi/dynamics365crm-python" seems newer, but it seems only to be able to handle standard objects, not custom objects.
Our current solution works with REST only.
import requests
import json
#set these values to retrieve the oauth token
crmorg = 'https://org.crm4.dynamics.com' #base url for crm org
clientid = '<id>' #application client id
client_secret = '<secret>'
username = 'dynamics-api#org.com' #username
userpassword = 'pw' #password
tokenendpoint = 'https://login.microsoftonline.com/bb23defa-be1d-4137-969b-324f8468f15a/oauth2/token' #oauth token endpoint
authorizationendpoint = 'https://login.microsoftonline.com/bb23defa-be1d-4137-969b-324f8468f15a/oauth2/authorize'
#build the authorization token request
tokenpost = {
'client_id':clientid,
'resource':crmorg,
'client_secret':client_secret,
'username':username,
'password':userpassword,
'grant_type':'password',
'oauthUrl':authorizationendpoint
}
#make the token request
tokenres = requests.post(tokenendpoint, data=tokenpost)
#set accesstoken variable to empty string
accesstoken = ''
#extract the access token
try:
accesstoken = tokenres.json()['access_token']
except(KeyError):
#handle any missing key errors
print('Could not get access token')
#set these values to query your crm data
crmwebapi = 'https://<org>.crm4.dynamics.com/api/data/v9.1' #full path to web api endpoint
crmwebapiquery = '/new_households' #web api query (include leading /)
#prepare the crm request headers
crmrequestheaders = {
'Authorization': 'Bearer ' + accesstoken,
'OData-MaxVersion': '4.0',
'OData-Version': '4.0',
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Prefer': 'odata.maxpagesize=500',
'Prefer': 'odata.include-annotations=OData.Community.Display.V1.FormattedValue'
}
#make the crm request
crmres = requests.get(crmwebapi+crmwebapiquery, headers=crmrequestheaders)
try:
#get the response json
crmresults = crmres.json()['value'][0]
#loop through it
for key,value in crmresults.items():
print (key, value)
except KeyError:
#handle any missing key errors
print('Could not parse CRM results')
Anyone know a package?
REST API is the way to go.
We use them every time with JavaScript and parase the response as Json.
Below is sample call which I perform within crm, you will see the response been transformed into Json
Don't worry much about details, for you important is this line var results = JSON.parse(this.response);
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/accounts?$select=accountcategorycode,accountclassificationcode,accountid,accountnumber,accountratingcode", false);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\",odata.maxpagesize=10");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var accountcategorycode = results.value[i]["accountcategorycode"];
var accountcategorycode_formatted = results.value[i]["accountcategorycode#OData.Community.Display.V1.FormattedValue"];
var accountclassificationcode = results.value[i]["accountclassificationcode"];
var accountclassificationcode_formatted = results.value[i]["accountclassificationcode#OData.Community.Display.V1.FormattedValue"];
var accountid = results.value[i]["accountid"];
var accountnumber = results.value[i]["accountnumber"];
var accountratingcode = results.value[i]["accountratingcode"];
var accountratingcode_formatted = results.value[i]["accountratingcode#OData.Community.Display.V1.FormattedValue"];
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();

Flask request.files is always empty

I am making a POST request to send a JSON object with keys containing files. An example of what I send to the backend is:
export interface PosInputFiles {
org: string;
year_month: string;
in_master_file: File;
iv_file?: File;
sales_file?: File;
recv_file?: File;
transfer_file?: File;
adjust_file?: File;
pcount_file?: File;
gift_file?: File;
xrate?: string;
}
My POST request looks like:
generateMaster(args: PosInputFiles) {
return this.http.post('http://localhost:5000/api', args, { headers: this.headers});
}
When I try to access these files from request.json, the values are an empty dict ({}).
try:
org = request.json['org']
year_month = request.json['year_month']
in_master_file = request.json['in_master_file']
iv_file = None if 'iv_file' not in request.json else request.json['iv_file']
sales_file = None if 'sales_file' not in request.json else request.json['sales_file']
recv_file = None if 'recv_file' not in request.json else request.json['recv_file']
transfer_file = None if 'transfer_file' not in request.json else request.json['transfer_file']
adjust_file = None if 'adjust_file' not in request.json else request.json['adjust_file']
pcount_file = None if 'pcount_file' not in request.json else request.json['pcount_file']
gift_file = None if 'gift_file' not in request.json else request.json['gift_file']
xrate = None if 'xrate' not in request.json else request.json['xrate']
except:
return { "post" : "failed" }
print(in_master_file)
print(len(request.files))
return { "post": "success"}
Then I tried sending only one file and made sure len(request.json) == 0 through POSTMan and my frontend (Angular8). However, len(request.files) is also 0 and every time I try to access something, there is 400 error. My POST request is successful as I always print {"post", "success"} but for some reason, no files make it to the backend. All my files sent are real files and I have made sure that I am sending the file. Thank you so much for your help!
For those who might have the same problem eventually, here's how I solved this issue. Flask doesn't recognize files that aren't of FormData type so that's why I could only access JSON. Thus, I had to append all my files to a FormData variable.
generateMaster(submittedFiles: PosInputFiles) {
const formData: FormData = new FormData();
Object.keys(submittedFiles).forEach(key => {
if (submittedFiles[key] instanceof File) {
formData.append(key, submittedFiles[key], submittedFiles[key].name);
} else {
formData.append(key, new File([], submittedFiles[key]), submittedFiles[key].name);
}
})
return this.http.post('http://localhost:5000/api', formData, { headers: this.headers});
}
Then backend will finally recognize the files. In order to get other string data, and floats, I stored those values as the filename and could access them as such.
def post(self):
# Initilize arguments
org = request.files.get('org').filename
year_month = request.files.get('year_month').filename
in_master_file = request.files.get('in_master_file')
iv_file = request.files.get('iv_file')
sales_file = request.files.get('sales_file')
...
xrate = None if 'xrate' not in request.files else float(request.files.get('xrate').filename)

Uncaught syntax error: unexpected string with json response

I'm getting an uncaught syntax error: unexpected string the chrome console when running ajax where I am trying to add a row to the bottom of a html table with the saved data returned with json. I really can't spot it....
function create_person() {
console.log("create person is working!")
$.ajax({
url : "{% url 'tande:create_person' %}",
type: "POST",
data: { first_name : $('#person-first-name').val(), surname : $('#person-surname').val(), email : $('#person-email').val(), coach_id : $('#person-coach-id').val(), is_coach : $('#person-is-coach').val(), position : $('#person-position').val(), contract_type : $('#person-contract').val()},
success : function(json) {
$('#person-first-name').val('');
$('#person-surname').val('');
$('#person-email').val('');
$('#person-coach-id').val('');
$('#person-is-coach').val('');
$('#person-position').val('');
$('#person-contract').val('');
console.log(json);
// ERROR OCCURS ON FOLLOWING LINE
var html = '<tr><td>'+json.personid+'</td><td>'+json.personfirstname+' '+json.personsurname'</td><td>'+json.personposition+'</td><td>'+json.personcontract+'</td><td>'+json.personemail+'</td><td>'+json.personcoachid+'</td></tr>';
console.log("success");
$('div#talk').html(html);
console.log(html)
},
error : function(xhr,errmsg,err) {
// $('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
// " <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log("uh oh");
}
});
};
The data is saved successfully and the json object is returned to the console, I just can't display it.
def create_person(request):
if request.method == "POST":
print "request post data in view"
firstname = request.POST.get('first_name')
print firstname
lastname = request.POST.get('surname')
emailadd = request.POST.get('email')
coachid = request.POST.get('coach_id')
isacoach = request.POST.get('is_coach')
positionheld = request.POST.get('position')
contracttype = request.POST.get('contract_type')
response_data = {}
starfruit = Person(first_name=firstname, surname=lastname, email=emailadd, coach_id=coachid, assign_as_coach=isacoach, position=positionheld, contract_type=contracttype)
starfruit.save()
response_data['personfirstname'] = starfruit.first_name
response_data['personsurname'] = starfruit.surname
response_data['personemail'] = starfruit.email
response_data['personcoachid'] = starfruit.coach_id
response_data['personiscoach'] = starfruit.assign_as_coach
response_data['personposition'] = starfruit.position
response_data['personcontract'] = starfruit.contract_type
response_data['personid'] = starfruit.id
# response_data = {
# ''
# }
print response_data
return JsonResponse(response_data)
else:
print "no post request in view"
return JsonResponse(response_data)
The error I'm getting in the console is just as follows:
(index):845 Uncaught SyntaxError: Unexpected string
and it refers to the line I've highlighted above
var html = '<tr><td>'+json.personid+'</td><td>'+json.personfirstname+' '+json.personsurname'</td><td>'+json.personposition+'</td><td>'+json.personcontract+'</td><td>'+json.personemail+'</td><td>'+json.personcoachid+'</td></tr>';
I'm unsure how else to approach this...
You're missing a + between json.personsurname and the following '</td><td>'.
Generally it's a really bad idea to build up HTML like that; this sort of thing is easy to miss.

JSON data not reaching view pyramid

I'm trying to build a page where when the user presses a button a variable which initially is 0 increments with 1. This number is then sent asynchronously to the server by using jQuery AJAX.
What I have so far is:
In my __init__.py file:
def main(global_config, **settings):
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind = engine)
Base.metadata.bind = engine
config = Configurator(settings = settings)
config.include('pyramid_jinja2')
config.add_static_view('static', 'static')
config.add_static_view('scripts', 'scripts')
# Removed the other views
config.add_route("declare_usage", '/user/{user_id}/{address_id}/declare')
config.add_route("declare_usage_json",'/user/{user_id}/{address_id}/declare.json')
config.scan()
My HTML + Jinja2:
#Removed code for simplicity
<div id="button_add">Add</div>
{{val}}
My JS:
$(document).ready(function(){
var room = 0;
jQuery.ajax({type:'POST',
url: '/user/1/5/declare', #I use a direct user ID and a direct address ID as I'm not sure how to send this to JS from Pyramid ... yet :).
data: JSON.stringify(room),
contentType: 'application/json; charset=utf-8'});
$('#button_add').click(function(){
room = room + 1;
});
});
My view code:
#view_config(route_name = 'declare_usage', renderer = 'declara.jinja2')
#view_config(route_name = 'declare_usage_json', renderer = 'json')
def declara_consum(request):
#Removed code for simplicity
val = request.POST.get('room') #I get a "None value in my html" if I change to request.json_body -> I get an error that there is no json to be parsed.
return { 'val' : val }
What happens is that when I open the debugger the POST request is successful with no data and on the page I get 2 options for 'val':
None -> When I use val = request.POST.get('room')
Error ValueError: No JSON object could be decoded -> When I use val = request.json_body
Also, still can't get it to work if in my JS i change url to be /user/1/5/declare.json and/or data to {'room' : room}
Can somebody please point out what I'm doing wrong?
you don't need another route declare_usage_json, just need separate two function like this
#view_config(route_name = 'declare_usage', renderer = 'declara.jinja2')
def declara_consum(request):
# this will response to your jinja2
return { 'val' : val }
#view_config(route_name = 'declare_usage', xhr=True, renderer = 'json')
def declara_consum_ajax(request):
# this will response to your asynchronously request
val = request.POST.get('room')
return { 'val' : val }
when you send a request using ajax, this will goto the second function.
$.ajax({
type: 'POST',
url: '/user/1/5/declare',
data: {'room' : room},
dataType: 'json'
}).done(function(response){
// update your data at html
});

Categories