I have an array of dictionaries in javascript that I want to send as payload to a POST request to flask.
However, the array always gets sent empty.
Javascript:
{% for department in departments %}
var department_id = "{{ department.id }}"
var cardgroup = $("#cardgroups_{{ department.id }}").val();
var doorgroup = $("#doorgroups_{{ department.id }}").val();
data.push({
department_id: department_id,
cardgroup_id: cardgroup,
doorgroup_id: doorgroup
});
{% endfor %}
$.post("data/save-office/"+office, data={data: data}, function (data) {
if (data['error']) {
alert(data['error']);
}
else
if (data['success']) {
load_table();
}
});
python:
#app.post('/data/save-office/<office>')
def save_office(office):
departments = request.args.getlist('data[]'). # departments = []
I tried to change departments to request.args.getlist('data') but it returned the same thing.
I also tried to use AJAX instead but it was basically the same thing.
Based on only provide an answer to your original question, you can pass an array to flask as the body of a POST request, Flask automatically handles JSON to dict conversion as-is.
Consider this code block as an example of how to send that data:
var my_json_array = [{
"key": "val"
}, {
"key": "val"
}]
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST', .
headers: {
'Content-Type': 'application/json'
},
body: data
});
return response.json();
}
postData('http://localhost:5000/test', my_json_array)
.then(data => {
console.log(data);
});
Note: I want to give credit to MDN for the fetch API sample I used on this post, visit https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch to know more about this new JavaScript API feature
Related
I am sending a FormData object to an endpoint. A phone number needs to be formatted as this JSON:
"phone": [{"type":"main", "value":"#"}, ...] or it gets rejected. A single object with a two-pair of keys and values in an array.
const doStuff = () => {
const formData = new FormData()
**Have tried below for setting key/value of phone object**
// Attempt 1
formData.set('phone', [{ type: 'main', value: '313-555-2121' }])
// Returns:
"phone":"[Object Object]"
// Attempt 2
formData.set(
'phone',
JSON.stringify([{ type: 'main', value: '313-555-2121' }])
)
// Returns
"phone":"[{\"type\":\"main\",\"value\":\"313-555-2121\"}]"
// Format as single "fields" object and stringify (results in fields: {...stuff}), API needs this.
const formattedForApi = JSON.stringify({fields: Object.fromEntries(formData.entries())})
// MAKE POST REQUEST...
}
The API errors on both of my attempts above. Complaining of an invalid first value which needs to be "main". Am I missing something with how stringify is affecting the data that is actually being sent?
For those wondering, the API is Podio
Digging into the PHP SDK code, it seems you're supposed to send the fields as plain old JSON and definitely not double-encoded
const formattedForApi = JSON.stringify({
fields: {
phone: [
{
type: "main",
value: "313-555-2121",
},
],
},
});
fetch(`/item/app/${app_id}/`, {
method: "POST",
body: formattedForApi,
headers: {
authorization: `OAuth2 ${token}`,
"content-type": "application/json",
},
});
Sending arrays as JSON in FormData is possible, but it requires encoding the arrays into strings before adding them to the FormData object. Here's an example in JavaScript:
const formData = new FormData();
const array = [1, 2, 3];
// Encode the array into a string
const encodedArray = JSON.stringify(array);
// Add the encoded array to the FormData object
formData.append("array", encodedArray);
// Send the FormData object in an HTTP request
fetch("https://example.com/api", {
method: "POST",
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
On the server-side, you can decode the string back into an array and use it as needed. The specific implementation will depend on the server-side language you're using.
my view is :
def creating_profile(request):
if request.is_ajax and request.method == "POST":
array = request.POST.get('nums')
print(request.POST.get('nums'))
else:
print('it's not ajax')
my js:
const RegisterForm = document.forms["RegisterForm"];
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
let nums = [1, 2, 3]
RegisterForm.addEventListener('submit', () => {
$.ajax({
headers: { 'X-CSRFToken': csrftoken },
url: '/account/creating-profile/',
type: 'POST',
data: { nums: nums },
success: function (data) {
//
}
});
but it returns None the result of print(request.POST.get('nums')), I would be glad if someone help me about this issue
update :
I'm not extremely familliar with Ajax, but whenever I try to pass data from a form to my view, I use FormData:
form_data = new FormData(document.getElementById("RegisterForm"))
This adds all fields of the form in a dictionnary, where you can access values by the field name. You can add on top of it using .append()
Then in your request you can use
fetch("/account/creating-profile/", {
headers: myHeaders,
body: form_data,
method:"POST"})
And retrieve it in your view using
nums = request.POST["nums"]
Edit :
Your JS would look like this :
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
let nums = [1, 2, 3]
myHeaders = new Headers()
myHeaders.append("X-CSRFToken", csrftoken)
form_data = new FormData(document.forms["RegisterForm"]);
form_data.append("nums", nums) // <-- Here you can add anything to the form data using form_data.append("Key", value)
fetch("/account/creating-profile/", {
headers: myHeaders,
body: form_data,
method:"POST"})
Doing so will POST on your server twice if you don't prevent default POST from happening, you can prevent it doing this :
$(function(){
$("#RegisterForm").submit(function(){
return false
})
})
or by using an event listenner and preventDefault (see docs : https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
You can use getlist() method to access list object in from POST like this
def creating_profile(request):
if request.is_ajax and request.method == "POST":
array = request.POST.getlist('nums')
print(array)# this will return [1, 2, 3]
else:
print('it's not ajax')
and about MultiValueDictKeyError it occurs if data is not present in your request.POST['key'] than raise MultiValueDictKeyError solution is
use get() method it will return None if given key does not have any value and will not raise any exception.
A data to be sent to the server. It can be JSON object, string or
array.
data: { "nums": nums }
check this doc.
I am trying to send a nested json data with get method using axios, but the problem is that the backend considers the children as a string.
const TOKEN = "token"
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': TOKEN,
},
data: {},
params: {
"page_id": 1,
"filter": {
"search": "name"
}
}
};
axios.get("http://localhost/api/pages", config)
What I get if I want to print filter in backend:
"{"search": "name"}"
You may have two options:
1- The first option is to decode the string you receive to json.
e.g.
---json_decode() in php
--- JSONObject() in java
--- JSON.parse() in nodejs
or any other method depending on your backend language...
2- The second option is to send your object in this format:
params: {
"page_id": 1,
"filter[search]": "name"
}
And pay attention not to put search in quotes!
You can use req.query on the server side:
function get(req, res, next) {
const { filter } = req.query;
console.log(filter);
...
}
Do a JSON.parse() of your Request.query.filter. Note that Request should be the request variable in your backend.
I am trying to send an AJAX post request to Django. I have a valid JSON object, which i can print/view/stringify in browser, but when it arrives in Django, the keys are unevaluated (see Django view in 2nd code block).
JS:
/* prettify payload for back */
var makeUpdatePayload = function(fieldType, fieldArray) {
var orderInfo = fieldArray.map(function(field, idx) {
var fieldInfo = field.split('-field-')
return {
'pk': fieldInfo[1],
'order': idx
}
});
return {[fieldType]: orderInfo}
};
/* post payload */
var updateFieldOrder = function( payload ) {
console.log('in ajax')
console.log(JSON.stringify(payload)) // {"search":[{"pk":"9","order":0},{"pk":"7","order":1},{"pk":"6","order":2},{"pk":"8","order":3},{"pk":"5","order":4},{"pk":"4","order":5}]}
$.ajax({
type: "POST",
url: "update_field_order/",
dataType: "json",
data: JSON.parse( JSON.stringify(payload)),
});
};
var payload = makeUpdatePayload('search', ["search-field-9", "search-field-7", "search-field-6", "search-field-8", "search-field-5", "search-field-4"])
updateFieldOrder(payload);
in my django view:
def update_field_order(request, recipe_pk):
print('post')
print(request.POST) # <QueryDict: {'search[0][pk]': ['9'], 'search[0][order]': ['0'], 'search[1][pk]': ['7'], 'search[1][order]': ['1'], 'search[2][pk]': ['6'], 'search[2][order]': ['2'], 'search[3][pk]': ['8'], 'search[3][order]': ['3'], 'search[4][pk]': ['5'], 'search[4][order]': ['4'], 'search[5][pk]': ['4'], 'search[5][order]': ['5']}>
I've tried JSON.stringify then JSON.parse -ing the payload before sending, but this doesn't help, I still see the same formatting. With JSON.stringify(payload), I get the expected output:
`<QueryDict: {'{"search":[{"pk":"9","order":0},{"pk":"7","order":1},{"pk":"6","order":2},{"pk":"8","order":3},{"pk":"5","order":4},{"pk":"4","order":5}]}': ['']}>`
Why is this happening?
I can see that the data is not correctly evaluated on sending:
I'm not entirely sure what you mean by the keys are unevaluated, but to send the object in the POST request, you should stringify it in your ajax call:
data: JSON.stringify(payload),
and then in your view, retrieve the JSON from the request.body and load it using the json module:
import json
...
payload = json.loads(request.body.decode("utf-8"))
So I have this code:
axios({
method: 'post',
url,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: {
json,
type,
}
})
Originally I had the normal axios.post but I changed to this because I thought it might have been a header problem. However I am still detecting nothing in my $_REQUEST nor $_POST. However, it is receiving data in file_get_contents("php://input").
Any idea what is wrong?
Edit
Okay I think I know what's wrong. It's posting it as a json object so it can only be read in the php://input. How do I change it to a normal string in axios?
From the documentation (I haven't preserved links in the quoted material):
Using application/x-www-form-urlencoded format
By default, axios serializes JavaScript objects to JSON.
PHP doesn't support JSON as a data format for populating $_POST.
It only supports the machine-processable formats natively supported by HTML forms:
application/x-www-form-urlencoded
multipart/form-data
To send data in the application/x-www-form-urlencoded format instead, you can use
one of the following options.
Browser
In a browser, you can use the URLSearchParams API as follows:
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
Note that URLSearchParams is not supported by all browsers, but there
is a polyfill available (make sure to polyfill the global
environment).
Alternatively, you can encode data using the qs library:
var qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));
Or you could customise your PHP so it can handle JSON as per this answer on another question.
var params = {
data1: 'string',
}
axios.post(url, params).then(function(response) {
//code here
});
or
axios.post(url, {data1: 'string' }).then(function(response) {
//code here
});
api
$_POST = json_decode(file_get_contents("php://input"),true);
echo $_POST['data1'];
To make things easier and universal if you ever decided to switch between AJAX libraries or server languages. With axios use the native JS FormData.
If you have your data in an object, you can convert it to FormData like this:
var myDataObj = {id:1, name:"blah blah"}
var formData = new FormData();
for (var key in myDataObj) {
formData.append(key, myDataObj[key])
}
Then you send the data:
axios.post('/sub/process.php', formData, {
params: { action: "update-user" },
headers: { 'Content-Type': 'multipart/form-data' },
baseURL: 'http://localhost',
}).then(data =>
console.log(data)
).catch(err => {
console.log(err)
return null
})
Notice, you can also send some info using params in axios that you can retrieve using $_GET. Also notice that I am using the baseURL in case you have different servers for the web page and your API endpoint.
You need to understand also that before axios send the real request, it performs a preflight request. A preflight request, is a mechanism in CORS by the browser to check if the resource destination is willing to accept the real request or not. Afterall, why would a request be sent when the target host is not willing to receive it anyway?
You have to make sure that your server has the right headers for your axios request, otherwise the preflight request will detect the incompatibility and stop your request:
//this is if you are using different different origins/servers in your localhost, * to be update with the right address when it comes to production
header('Access-Control-Allow-Origin: *');
//this is if you are specifying content-type in your axios request
header("Access-Control-Allow-Headers: Content-Type");
Now, you will able to access your sent data in the $_POST variable:
echo "<pre>";
print_r($_POST);
echo "</pre>";
Additionally, axios allows you to send data in different formats. you can send a json for example like this:
axios.post('/sub/process.php', { id: "1", name:"blablah" }, {
params: { action: "update-item" },
headers: { 'Content-Type': 'application/json' },
baseURL: 'http://localhost',
}).then(data =>
console.log(data)
).catch(err => {
console.log(err)
return null
})
In the PHP side, this can be accessed as follows:
$data = json_decode(file_get_contents("php://input"),true);
echo "<pre>";
print_r($data);
echo "</pre>";
Using PHP std object
Using PHP std object structure to get the variables of the post.
On the client:
axios.post(url, {id: 1 , Name:'My Name' }).then(function(response) {
console.log(response.data);
});
On the server
$obj = json_decode(file_get_contents('php://input'));
$id = $obj->id;
$Name = $obj->Name;
//test by returning the same values
$retObj=(object)["id"=>$id,"Name"=>$Name]
echo json_encode($retObj);
Both jQuery and Axios using same PHP file
if you have a file receiving post both from axios and jquery you may use:
if($_SERVER['REQUEST_METHOD']==='POST' && empty($_POST)) {
$_POST = json_decode(file_get_contents('php://input'),true);
}
to convert the Axios json-serialized posts to the $_POST array
This code works on browser/node both today.
I think this is more practical.
I tested this code on node.js and passed the data variable to PHP8 using $_POST['param1'] and it worked perfectly.
function axqs(d){
let p = new URLSearchParams();
Object.keys(d).forEach(function(key){
p.append(key, this[key]);
}, d);
return p
}
let data = {
'param1': 'value1',
'param2': 'value2',
}
let p = axqs(data)
axios.post('/foo', p)
Just wanted to share my insights, I was facing a similar problem and solved it by the following code set
JS
const instructions_str = {
login: {
"type": "devTool",
"method": "devTool_login",
"data": {
"username": "test",
"password": "Test#the9"
}
},
tables: {
"type": "devTool",
"method": "devTool_get_all_tables",
"data": ""
}
};
const body = {
firstName: 'Fred',
lastName: 'Flintstone',
name: "John",
time: "2pm",
instructions : JSON.stringify(instructions_str)
};
function decodeData(data) {
const serializedData = []
for (const k in data) {
if (data[k]) {
serializedData.push(`${k}=${encodeURIComponent(data[k])}`)
}
}
return serializedData.join('&')
};
const body2 = decodeData(body);
axios.post('URL', body2)
.then(response => {
console.log("contextApi got it", response);
}).catch(error => {
console.log("contextApi error.response", error.response);
});
PHP
// set content return type
header('Content-Type: application/json');
// Setting up some server access controls to allow people to get information
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Methods: POST, GET');
// This way I can check and see what I sent
$postVars_array = $_POST ?? parse_str(file_get_contents("php://input"),$postVars_array) ?? [];
echo json_encode($postVars_array);
I also found this github page very helpful https://github.com/axios/axios/issues/1195