Accessing nested objects in django POST request using python 3 - python

I am having some trouble accessing nested objects from an ajax post call. Here is my js:
$.ajax({
url: "/api/locate/",
type: "POST",
data: {start:
{
latitude: position.coords.latitude,
longitude: position.coords.longitude
}
},
dataType: 'json',
contentType: "application/x-www-form-urlencoded",
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
console.log(start);
},
success: function(data) {
console.log(data);
}
})
in my views, the only way I can retrieve the data is by doing the following:
latitude = request.POST['start[latitude]']
longitude = request.POST['start[longitude]']
which is kinda bad considering that optimally I'd like to have start as the dictionary containing the latitude and longitude keys. I do realize this formatting is due to the content type being set to "application/x-www-form-urlencoded", but when I change it to "application/json", the data must be decoded from request.body:
decoded = request.body.decode('utf8')
data = json.loads(decoded)
which in turn raises the following ValueError:
Expecting value: line 1 column 1 (char 0)
The decoded string is:
start%5B0%5D%5Blatitude%5D=31.736784000000004&start%5B0%5D%5Blongitude%5D=-106.473027
Has any of you had any luck on properly loading nested objects or am I stuck with the first method?
EDIT: Using Django 1.6.2 and python 3.4

When you send json data, use the JSON stringifier on your object.
data: JSON.stringify({start:
{
latitude: position.coords.latitude,
longitude: position.coords.longitude
}
})
If you pass a plain Object as data, it is converted to a query string, no matter what you declare as Content-Type.

Related

how convert a python post call to restsharp

Check the two part of code bellow. There is two method second one is python method which make a post request to a url but i want to do same api call with same payload with c# restsharp. I already tried to convert code like bellow but since i don't have idea about python i am not able to understand how can i add payload as its done in python code. I already tried to add this payload using request.AddBody but it is not same as it was done in python code. How can i add those payload info with restsharp request exactly as done in py? please advice
payload:
data={
"locationType": "LOCATION_INPUT",
"zipCode": zip_code,
"storeContext": "generic",
"deviceType": "web",
"pageType": "Gateway",
"actionSource": "glow",
"almBrandId": "undefined",
}
C#
public static IRestResponse MakeApiCall(string zip_code)
{
var client = new RestClient("https://www.example.com");
var request = new RestRequest(Method.POST);
//request.AddHeader();//i can add header like this thats not a problem
//request.AddCookie();//i can add cookie like this thats not a problem
request.AddBody("data=", #"{" +
"locationType\": \"LOCATION_INPUT",
"zipCode\": zip_code,
"storeContext\": \"generic",
"deviceType\": \"web",
"pageType\": \"Gateway",
"actionSource\": \"glow",
"almBrandId\": \"undefined");
var result = client.Execute(request);
return result;
}
Python:
def MakeApiCall(zip_code: str, headers: dict, cookies: dict):
response = requests.post(
url="https://www.example.com",
data={
"locationType": "LOCATION_INPUT",
"zipCode": zip_code,
"storeContext": "generic",
"deviceType": "web",
"pageType": "Gateway",
"actionSource": "glow",
"almBrandId": "undefined",
},
headers=headers,
cookies=cookies,
)
assert response.json()["isValidAddress"], "Invalid change response"
return response.cookies
If I understood your question correctly, you are trying to convert the method from python into a C# method. I am assuming that you are using .NET Core and the RestSharp library, if not you need to clarify what you are using in your original post.
In your class instantiate the RestClient class in a constructor
public class RandomClass
{
private readonly IRestClient _client;
public RandomClass(){
_client = new RestClient("baseUrl");
_client.UseSerializer(
() => new JsonSerializer { DateFormat = "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ" }
);
}
}
Now, define a class for your request data:
public class Location {
public string LocationType {get; set;}
public string ZipCode {get; set;}
public string StoreContext {get; set; }
public string DeviceType {get; set;}
public string ActionSource {get; set;}
public string BrandId {get; set;}
}
In your MakeApiCall method:
public IRestResponse MakeApiCall(Location data){
var request = _client.Request("/endpoint/relative/to/baseUrl", Method.POST);
var jsonToSend = JsonSerializer.Serialize(data);
request.AddParameter(
"application/json; charset=utf-8",
jsonToSend,
ParameterType.RequestBody
);
var response = _client.Execute(request);
if (response.ErrorException != null)
{
const string message = "Error retrieving response.";
throw new Exception(message, response.ErrorException);
}
// if we get to here then the request succeeded
return response.data;
}
I haven't tested it, but nonetheless it should point you in the right direction.
There are two ways to go about it.
Use a strongly typed data structure
Create a dynamic object and use that as your data object.
Create a class to store your data object
class MyDataType
{
[JsonProperty("locationType")]
public string LocationType { get; set; }
[JsonProperty("zipCode")]
public string ZipCode { get; set; }
//...
}
// and in your method, you would use the above datatype like this,
var data = new MyDataType
{
LocationType = "location",
ZipCode = "zipCode"
// ...
};
or 2. Create a dynamic / anonymous object and use that as json body.
var data = new
{
locationType = "location",
zipCode = "zipCode",
storeContext = "generic",
deviceType = "web",
pageType = "Gateway",
actionSource = "glow",
almBrandId = "undefined",
};
Once you have your object, I would recommend using AddJsonBody as AddBody is deprecated.
var client = new RestClient("https://www.example.com");
var request = new RestRequest(Method.POST);
request.AddHeader(#"Content-Type", #"application/json");
request.AddHeader(#"Accept", #"application/json");
request.AddJsonBody(data);
var result = client.Execute(request);
string actualData = result.Content;
result.Content would have your response. You can use Newtonsoft Json to convert data in your response to a class object and validate your data that way.

Decoding Django POST request body

I'm building an mapping app using cordova and making a post request sending the following JSON (feature)
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-6.6865857,
53.2906136
]
},
"properties": {
"amenity": "pub",
"name": "The Parade Ring"
}
}
This is the JQuery code sending the request
function savePub(feature){
$.ajax({
type: "POST",
headers: {"csrfmiddlewaretoken": csrftoken},
url: HOST + URLS["savePub"],
data: {
pub_feature: JSON.stringify(feature)
},
contentType:"application/json; charset=utf-8"
}).done(function (data, status, xhr) {
console.log(data + " " + status);
pubDialogAlert("Pub saved",feature);
}).fail(function (xhr, status, error) {
showOkAlert(error);
console.log(status + " " + error);
console.log(xhr);
}).always(function () {
$.mobile.navigate("#map-page");
});
}
When the request is received in the Django backend I am not sure why when I print the request body it looks like this,
b'pub_feature=%22%7B%5C%22type%5C%22%3A%5C%22Feature%5C%22%2C%5C%22geometry%5C%22%3A%7B%5C%22type%5C%22%3A%5C%22Point%5C%22%2C%5C%22coordinates%5C%22%3A%5B-6.6865857%2C53.2906136%5D%7D%2C%5C%22properties%5C%22%3A%7B%5C%22amenity%5C%22%3A%5C%22pub%5C%22%2C%5C%22name%5C%22%3A%5C%22The+Parade+Ring%5C%22%7D%7D%22'
and when I try to decode it and then use json.loads() it throws this error
#api_view(['POST'])
def save_pub(request):
if request.method == "POST":
data = request.body.decode('utf-8')
received_json_data = json.loads(data)
return Response(str(received_json_data) + " written to db", status=status.HTTP_200_OK)
JSONDecodeError at /savepub/
Expecting value: line 1 column 1 (char 0)
I am assuming because once it decodes the binary string it can't be converted to valid JSON because of those characters %22 etc, but I don't know what the solution is.
Any help would be appreciated.
Thanks
You're mixing up two things here, form-encoded and JSON format. What you have is a form-encoded post with one key, pub_feature, whose value is a JSON object.
Instead you should post the JSON directly:
data: JSON.stringify(feature),
and then you should be able to load it as you do already - although note that really you should let DRF deal with that for you

Passing Dict of Arrays using Ajax and Django

I have a dictionary of arrays that I would like to pass to my Django view.
$.ajax({
url: '/fund_monitor/fund_directory',
type: 'GET',
data:{
filter_dict: filter_dict,
},
success: function (data) {
console.log(filter_dict);
}
});
And in my view I would like to receive this dict:
if request.is_ajax():
filter_dict = request.GET.getlist('filter_dict')
print("Is Ajax", filter_dict)
But "Is Ajax []" gets printed out and just as an example, my filter_dict:
Designated Broker:["BMO"]
Fund Class:["OM"]
Any ideas why a blank array gets passed?
$.ajax({
url: '/fund_monitor/fund_directory',
type: 'GET',
data:JSON.stringify({
filter_dict: filter_dict,
}),
success: function (data) {
console.log(filter_dict);
}
});
if request.is_ajax():
request_data = json.loads(request.GET)
filter_dict = request_data['filter_dict']
print("Is Ajax", filter_dict)

Unclear 404 get ajax error passing integer to django

Totally unclear 404 Ajax error.
var int_page_number = 2;
$.ajax({
type:'GET',
url: '/loadmore/',
data: { 'page_number' : int_page_number},
dataType: 'json',
success: function (data) {
alert(data);
}
});
In the place passing data, I tried both using apostrophe and not around page_number. It's 404 so error may be in frontedn, but anyways I attach django urls.py string just in case :
url(r'^loadmore/(?P<page_number>[0-9]+)/$', views.loadmore),
and views.py function, which is all right:
#api_view(['GET', ])
def loadmore(request,page_number):
answers_to_questions_objects = Question.objects.filter(whom=request.user.profile).filter(answered=True).order_by('-answered_date')
paginator = Paginator(answers_to_questions_objects,10)
current_page = (paginator.page_number)
answers = serializers.serialize('json', current_page)
data = {
'answers': answers
}
return Response(data)`
For your url you should make a call to the url like /loadmore/2/, but you make the call like /loadmore/?page_number=2. So your ajax should be like this:
var int_page_number = 2;
$.ajax({
type:'GET',
url: '/loadmore/' + int_page_number + '/',
success: function (data) {
alert(data);
}
});

Handling a nested array in Flask request

I built a webserver in Flask and I'm passing in the request using jsonp. One of the things I pass in is an nested array and when I retrieve the data in Flask, the array is completely messed up.
Here's my code
index.html
var array = [[2,1],[2,2],[2,3]]
function getNext() {
var data = {
'M': 5,
'N': 5,
'array' : array
};
$.ajax({
url: '/getNewGeneration',
jsonp: 'callback',
dataType: 'jsonp',
data: data,
success: function(response) {
...
}
});
}
server.py
#app.route('/getNewGeneration')
def getNext():
M = request.args.get('M')
N = request.args.get('N')
liveCells = request.args.get('liveCells')
...
When I print out request.args I get ImmutableMultiDict([('callback', u'jQuery17101683842277548142_1412736365518'), ('array[2][]', u'2'), ('array[2][]', u'3'), ('array[1][]', u'2'), ('array[1][]', u'2'), ('N', u'5'), ('M', u'5'), ('_', u'1412736417145'), ('array[0][]', u'2'), ('array[0][]', u'1')])
Does anyone know how to fix this?
I see two problems with your code. First, you don't pass a key named 'liveCells'. You pass one named 'array'. You need to update this either in your JavaScript or on the Flask side. Assuming you want the former, your JavaScript should look like
var array = [[2,1],[2,2],[2,3]]
function getNext() {
var data = {
'M': 5,
'N': 5,
'liveCells' : array
};
$.ajax({
url: '/getNewGeneration',
jsonp: 'callback',
dataType: 'jsonp',
data: data,
success: function(response) {
...
}
});
}
Second, you can't use the get method to retrieve multivalve keys. ImmutableMultiDicts, such as request.args, provide a method called getlist that will return a list of items for the given key rather than a single value. Update your code to
liveCells = request.args.getlist('liveCells')
More information can be found in the werkzeug documentation.
Do it like this and i think it will work for you.
$.ajax({
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
url: 'getNewGeneration',
success: function (e) {
console.log(e);
}
});
And try to print request.json then.

Categories

Resources