I am using django-tastypie to implement restapi, i am using sencha as a mobile client . I need to manipulate the response text for some purpose.
Like below
form.submit({
success: function() {
// The callback function is run when the user taps the 'ok' button
form.reset();
//Ext.Msg.alert('Thank You', 'Your message has been received', function() {
// form.reset();
//});
}
});
I have json response as follows
{"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 13},
"objects": [{"body": "This will prbbly be my lst edited post.", "id": 1,
"pub_date": "2011-05-22", "resource_uri": "/api/v1/entry/1/", "slug": "another-post",
"title": "Another Post"}, {"body": "This will prbbly be my lst post.", "id": 2,
"pub_date": "2011-05-22", "resource_uri": "/api/v1/entry/2/", "slug": "another-post",
"title": "Another Post"}, {"body": "This will prbbly be my lst edited post"}]}
It is very important to send success => true
If, success is not defined or not equal to true then it will be considered as a form submit error.
How to append success=true on django tastypie json
If I understand your question correctly, you want to append {'success': true} to the result of API calls, correct? If so, you can override the dehydrate method on your Resource class:
def dehydrate(self, bundle):
bundle.data['success'] = True
return bundle
Related
I am working on a new project in HubSpot that returns nested JSON like the sample below. I am trying to access the associated contacts id, but am struggling to reference it correctly (the id I am looking for is the value '201' in the example below). I've put together this script, but this script only returns the entire associations portion of the JSON and I only want the id. How do I reference the id correctly?
Here is the output from the script:
{'contacts': {'paging': None, 'results': [{'id': '201', 'type': 'ticket_to_contact'}]}}
And here is the script I put together:
import hubspot
from pprint import pprint
client = hubspot.Client.create(api_key="API_KEY")
try:
api_response = client.crm.tickets.basic_api.get_page(limit=2, associations=["contacts"], archived=False)
for x in range(2):
pprint(api_response.results[x].associations)
except ApiException as e:
print("Exception when calling basic_api->get_page: %s\n" % e)
Here is what the full JSON looks like ('contacts' property shortened for readability):
{
"results": [
{
"id": "34018123",
"properties": {
"content": "Hi xxxxx,\r\n\r\nCan you clarify on how the blocking of script happens? Is it because of any CSP (or) the script will decide run time for every URL’s getting triggered from browser?\r\n\r\nRegards,\r\nLogan",
"createdate": "2019-07-03T04:20:12.366Z",
"hs_lastmodifieddate": "2020-12-09T01:16:12.974Z",
"hs_object_id": "34018123",
"hs_pipeline": "0",
"hs_pipeline_stage": "4",
"hs_ticket_category": null,
"hs_ticket_priority": null,
"subject": "RE: call followup"
},
"createdAt": "2019-07-03T04:20:12.366Z",
"updatedAt": "2020-12-09T01:16:12.974Z",
"archived": false
},
{
"id": "34018892",
"properties": {
"content": "Hi Guys,\r\n\r\nI see that we were placed back on the staging and then removed again.",
"createdate": "2019-07-03T07:59:10.606Z",
"hs_lastmodifieddate": "2021-12-17T09:04:46.316Z",
"hs_object_id": "34018892",
"hs_pipeline": "0",
"hs_pipeline_stage": "3",
"hs_ticket_category": null,
"hs_ticket_priority": null,
"subject": "Re: Issue due to server"
},
"createdAt": "2019-07-03T07:59:10.606Z",
"updatedAt": "2021-12-17T09:04:46.316Z",
"archived": false,
"associations": {
"contacts": {
"results": [
{
"id": "201",
"type": "ticket_to_contact"
}
]
}
}
}
],
"paging": {
"next": {
"after": "35406270",
"link": "https://api.hubapi.com/crm/v3/objects/tickets?associations=contacts&archived=false&hs_static_app=developer-docs-ui&limit=2&after=35406270&hs_static_app_version=1.3488"
}
}
}
You can do api_response.results[x].associations["contacts"]["results"][0]["id"].
Sorted this out, posting in case anyone else is struggling with the response from the HubSpot v3 Api. The response schema for this call is:
Response schema type: Object
String results[].id
Object results[].properties
String results[].createdAt
String results[].updatedAt
Boolean results[].archived
String results[].archivedAt
Object results[].associations
Object paging
Object paging.next
String paging.next.after
String paging.next.linkResponse schema type: Object
String results[].id
Object results[].properties
String results[].createdAt
String results[].updatedAt
Boolean results[].archived
String results[].archivedAt
Object results[].associations
Object paging
Object paging.next
String paging.next.after
String paging.next.link
So to access the id of the contact associated with the ticket, you need to reference it using this notation:
api_response.results[1].associations["contacts"].results[0].id
notes:
results[x] - reference the result in the index
associations["contacts"] -
associations is a dictionary object, you can access the contacts item
by it's name
associations["contacts"].results is a list - reference
by the index []
id - is a string
In my case type was ModelProperty or CollectionResponseProperty couldn't reach dict anyhow.
For the record this got me to go through the results.
for result in list(api_response.results):
ID = result.id
I was coding a webapp based on GPT-2 but it was not good so I decided to switch to official OpenAI GPT-3.
So I make that request:
response = openai.Completion.create(
engine="davinci",
prompt="Hello",
temperature=0.7,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
And when I print the response I get this:
{
"choices": [
{
"finish_reason": "length",
"index": 0,
"logprobs": null,
"text": ", everyone, and welcome to the first installment of the new opening"
}
],
"created": 1624033807,
"id": "cmpl-3CBfb8yZAFEUIVXfZO90m77dgd9V4",
"model": "davinci:2020-05-03",
"object": "text_completion"
}
But I only want to print the text, so how can I do to print the "text" value in the response list.
Thank you in advance and have a good day.
Using the dict indexing by key, and the list indexing by index
x = {"choices": [{"finish_reason": "length",
"text": ", everyone, and welcome to the first installment of the new opening"}], }
text = x['choices'][0]['text']
print(text) # , everyone, and welcome to the first installment of the new opening
You can try print(response["choices"][0]["text"])
Hope this helps.
I think GPT-3 response structure has been changed, for reference, the response object looks this:
const response = await openai.createCompletion({
model: "text-davinci-002",
prompt: "Say this is a test",
temperature: 0,
max_tokens: 6,
});
// the response looks like the following
{
status: 200,
statusText: 'OK',
headers: {
},
config: {
},
request: <ref *1> ClientRequest {
},
data: {
id: 'cmpl-5zzyzqvh4Hmi5yyNL2LMI9ADkLBU0',
object: 'text_completion',
created: 1665457953,
model: 'text-davinci-002',
choices: [ [Object] ],
usage: { prompt_tokens: 5, completion_tokens: 6, total_tokens: 11 }
}
}
// choices can be accessed like this
var { choices } = { ...response.data }
I have defined the following function in the backend for getting JSON responses
def create(self, request, *args, **kwargs):
import requests
import json
url = request.POST.get('url')
r = requests.get(url)
return Response(json.loads(r.content.decode('utf-8')))
It works perfectly when used outside of a django view (if i remove all the function arguments and pass in a url)
This is the output when sending a sample request to the Twitter API
{
"url": "https://twitter.com/elonmusk/status/1285830270709403648",
"author_name": "Elon Musk",
"author_url": "https://twitter.com/elonmusk",
"html": "<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">You don’t have a soul, you are a soul</p>— Elon Musk (#elonmusk) July 22, 2020</blockquote>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n",
"width": 550,
"height": null,
"type": "rich",
"cache_age": "3153600000",
"provider_name": "Twitter",
"provider_url": "https://twitter.com",
"version": "1.0"
}
No only do the strings get wrapped in double quotes \ \ but also arguments like \n , blockquote are kept in the response
I know it has something to do with the response beeing serialized multiple times but I can't find exactly when this happens
Slightly Modifying the response to return the raw data returns this
return Response({
"json_serialized" : json.loads(r.content.decode('utf-8')),
"raw_content" : r.content.decode('utf-8')
})
Here is the output
{
"json_serialized": {
"url": "https://twitter.com/elonmusk/status/1285830270709403648",
"author_name": "Elon Musk",
"author_url": "https://twitter.com/elonmusk",
"html": "<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">You don’t have a soul, you are a soul</p>— Elon Musk (#elonmusk) July 22, 2020</blockquote>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n",
"width": 550,
"height": null,
"type": "rich",
"cache_age": "3153600000",
"provider_name": "Twitter",
"provider_url": "https://twitter.com",
"version": "1.0"
},
"raw_content": "{\"url\":\"https:\\/\\/twitter.com\\/elonmusk\\/status\\/1285830270709403648\",\"author_name\":\"Elon Musk\",\"author_url\":\"https:\\/\\/twitter.com\\/elonmusk\",\"html\":\"\\u003Cblockquote class=\\\"twitter-tweet\\\"\\u003E\\u003Cp lang=\\\"en\\\" dir=\\\"ltr\\\"\\u003EYou don’t have a soul, you are a soul\\u003C\\/p\\u003E— Elon Musk (#elonmusk) \\u003Ca href=\\\"https:\\/\\/twitter.com\\/elonmusk\\/status\\/1285830270709403648?ref_src=twsrc%5Etfw\\\"\\u003EJuly 22, 2020\\u003C\\/a\\u003E\\u003C\\/blockquote\\u003E\\n\\u003Cscript async src=\\\"https:\\/\\/platform.twitter.com\\/widgets.js\\\" charset=\\\"utf-8\\\"\\u003E\\u003C\\/script\\u003E\\n\",\"width\":550,\"height\":null,\"type\":\"rich\",\"cache_age\":\"3153600000\",\"provider_name\":\"Twitter\",\"provider_url\":\"https:\\/\\/twitter.com\",\"version\":\"1.0\"}"
}
- The first one is the same of course,
This is not a problem with the Twitter API
The same happens with any json response
Here is an example with the Facebook API
{
"json_serialized": {
"author_name": "Unboxholics",
"author_url": "https://www.facebook.com/Unboxholics/",
"provider_url": "https://www.facebook.com",
"provider_name": "Facebook",
"success": true,
"height": null,
"html": "<div id=\"fb-root\"></div>\n<script async=\"1\" defer=\"1\" crossorigin=\"anonymous\" src=\"https://connect.facebook.net/el_GR/sdk.js#xfbml=1&version=v7.0\" nonce=\"OAmlb4oU\"></script><div class=\"fb-post\" data-href=\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\" data-width=\"552\"><blockquote cite=\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\" class=\"fb-xfbml-parse-ignore\"><p>🤘8 ΧΡΟΝΙΑ UNBOXHOLICS🎂\nΣήμερα γιορτάζουν τα κωλόμπουρα! Σήμερα γιορτάζουμε μαζί αυτήν την ημέρα! Σας ευχαριστούμε από...</p>Δημοσιεύτηκε από Unboxholics στις Τετάρτη, 22 Ιουλίου 2020</blockquote></div>",
"type": "rich",
"version": "1.0",
"url": "https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3",
"width": 552
},
"raw_content": "{\"author_name\":\"Unboxholics\",\"author_url\":\"https://www.facebook.com/Unboxholics/\",\"provider_url\":\"https://www.facebook.com\",\"provider_name\":\"Facebook\",\"success\":true,\"height\":null,\"html\":\"\\u003Cdiv id=\\\"fb-root\\\">\\u003C/div>\\n\\u003Cscript async=\\\"1\\\" defer=\\\"1\\\" crossorigin=\\\"anonymous\\\" src=\\\"https://connect.facebook.net/el_GR/sdk.js#xfbml=1&version=v7.0\\\" nonce=\\\"OAmlb4oU\\\">\\u003C/script>\\u003Cdiv class=\\\"fb-post\\\" data-href=\\\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\\\" data-width=\\\"552\\\">\\u003Cblockquote cite=\\\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\\\" class=\\\"fb-xfbml-parse-ignore\\\">\\u003Cp>\\ud83e\\udd188 \\u03a7\\u03a1\\u039f\\u039d\\u0399\\u0391 UNBOXHOLICS\\ud83c\\udf82\\n\\u03a3\\u03ae\\u03bc\\u03b5\\u03c1\\u03b1 \\u03b3\\u03b9\\u03bf\\u03c1\\u03c4\\u03ac\\u03b6\\u03bf\\u03c5\\u03bd \\u03c4\\u03b1 \\u03ba\\u03c9\\u03bb\\u03cc\\u03bc\\u03c0\\u03bf\\u03c5\\u03c1\\u03b1! \\u03a3\\u03ae\\u03bc\\u03b5\\u03c1\\u03b1 \\u03b3\\u03b9\\u03bf\\u03c1\\u03c4\\u03ac\\u03b6\\u03bf\\u03c5\\u03bc\\u03b5 \\u03bc\\u03b1\\u03b6\\u03af \\u03b1\\u03c5\\u03c4\\u03ae\\u03bd \\u03c4\\u03b7\\u03bd \\u03b7\\u03bc\\u03ad\\u03c1\\u03b1! \\u03a3\\u03b1\\u03c2 \\u03b5\\u03c5\\u03c7\\u03b1\\u03c1\\u03b9\\u03c3\\u03c4\\u03bf\\u03cd\\u03bc\\u03b5 \\u03b1\\u03c0\\u03cc...\\u003C/p>\\u0394\\u03b7\\u03bc\\u03bf\\u03c3\\u03b9\\u03b5\\u03cd\\u03c4\\u03b7\\u03ba\\u03b5 \\u03b1\\u03c0\\u03cc \\u003Ca href=\\\"https://www.facebook.com/Unboxholics/\\\">Unboxholics\\u003C/a> \\u03c3\\u03c4\\u03b9\\u03c2 \\u003Ca href=\\\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\\\">\\u03a4\\u03b5\\u03c4\\u03ac\\u03c1\\u03c4\\u03b7, 22 \\u0399\\u03bf\\u03c5\\u03bb\\u03af\\u03bf\\u03c5 2020\\u003C/a>\\u003C/blockquote>\\u003C/div>\",\"type\":\"rich\",\"version\":\"1.0\",\"url\":\"https://www.facebook.com/Unboxholics/photos/a.647580348625155/3017945248255308/?type=3\",\"width\":552}"
}
It's not an issue of DRF. It's a very common issue when deserializing JSON data.
The simplest way is to make your own deserializing method using json.loads method.
For example,
def deserialize(data: str) -> Any:
return json.loads(data).replace('\\"', '\"').replace('\\n', '\n')
There are many articles and answers about this. See Python: json.loads chokes on escapes for more detailed answer.
So I'm pretty new to implementing flask-restplus and I have encountered this road block.
I have read the restplus docs over and over again and followed several exampled. But the behavior that I'm facing is very much different from what is supposed to be.
So I have a model that is supposed to be a list of objects of another model (returned from the function drone_model()).
drones_list = api.model('drones_list', {
'items': fields.List(fields.Nested(drone_model())),
'message':fields.String(''),
'code': fields.Integer('')
})
Everything works fine, no errors. But when I try the API (http://127.0.0.1:5000/datamine/v2/drones), as a response I get the Marshalling model back instead of the data itself. If I print the data, it gets printed, but for some reason in the web, the restplus model is returned.
Below I have the code that I had written. If I take the marshal_with decorator off, then the data is returned just fine.
#api.route('/')
class DronesList(Resource):
#api.marshal_with(drones_list, envelope='data')
#api.response(200, 'All drones successfully fetched!')
def get(self):
"""
Get all drones!.
"""
from app.utils.common import get_start_end_date_from_request
start_date, end_date = get_start_end_date_from_request(request)
drones = []
for drone in Drone.objects:
drones.append({
'id': str(drone.id),
'serial_id': drone.serial_id,
'maintenances': [],
'status': get_dynamic_status(drone, start_date, end_date),
'picture_url': drone.asset.picture_url,
'manufacturer': drone.asset.manufacturer,
'model_name': drone.asset.model_name,
'drone_type': drone.asset.drone_type,
'payload_type': drone.asset.payload_type,
'asset_url': drone.get_url(drone.id)
})
success = ClientSuccessFunctionClass('All drones successfully fetched!', 200, drones)
return (success.to_dict())
These are the outputs on the browser:
1. Without the marshal decorator:
{
"data": {
"items": [
{
"id": "5aeafcb93a33683f73827e91",
"serial_id": "Drone 1",
"maintenances": [],
"status": "Decommissioned",
"picture_url": "some img url",
"manufacturer": "DJI",
"model_name": "Phantom 4 Pro",
"drone_type": "Quadcopter",
"payload_type": "RGB Camera",
"asset_url": "http://127.0.0.1:5000/datamine/v1/drones/5aeafcb93a33683f73827e91"
},
{
"id": "5aeaff374f85747f90df2714",
"serial_id": "Drone 2",
"maintenances": [],
"status": "Available",
"picture_url": "sime url",
"manufacturer": "DJI",
"model_name": "Phantom 4",
"drone_type": "Quadcopter",
"payload_type": "RGB Camera",
"asset_url": "http://127.0.0.1:5000/datamine/v1/drones/5aeaff374f85747f90df2714"
}
],
"message": "All drones successfully fetched!",
"code":200
}
}
2. With the marshal decorator:
{
"data": {
"items": [
{
"id": "Id of Drone",
"serial_id": "Name of Drone",
"status": "Status of Drone",
"maintenances": null,
"picture_url": "Picture URL",
"manufacturer": "Manufacturer of Drone",
"model_name": "Model name of Drone",
"drone_type": "Type of Drone",
"payload_type": "Payload type of Drone",
"asset_url": "Asset URL of Drone"
}
],
"message": "",
"code": ""
}
}
It would be really helpful if someone could tell me what I'm doing wrong as I need to recive the output as the one shown in snippet of the output without the decorator.
Thank you.
Here is a diagram showing invocation order from top to bottom to help make sense of what is happening:
get()
→ api.response(200, 'All drones successfully fetched!') # documents the response
→ api.marshal_with(drones_list, envelope='data')` # returns marshalled dict
The result from invoking get is passed to the api.response decorator function whose result is passed on to api.marshal_with decorator function.
Looking at the shape of the dictionary returned from invoking get()
{
data {
items [
{
id,
serial_id,
maintenances,
status,
picture_url,
manufacturer,
model_name,
drone_type,
payload_type,
asset_url
}
],
message,
code
}
}
The message and code in the response are nested inside of the data.
You need to model the data appropriately, to be able to marshal it. This can be done by passing an argument for what field to look up in the marshal dictionary.
drones_list = api.model('drones_list', {
'items': fields.List(fields.Nested(drone_model()), attribute='data.items'),
'message':fields.String(attribute='data.message'),
'code': fields.Integer(attribute='data.code')
})
As you can see, it's pretty redundant applying the api.marshal_with decorator function on the view given that it's only unnests then nests the result in data field.
I'm running the code below and it takes the user to PayPal to make a payment and then returns them to the return_url as expected. However the code doesn't execute any further and it doesn't execute the payment.
I have based my code on https://github.com/paypal/rest-api-sdk-python:
class PayPalHandler(tornado.web.RequestHandler):
def get(self):
logging.basicConfig(level=logging.INFO)
paypal.configure({
"mode": PAYPAL_MODE,
"client_id": PAYPAL_CLIENT_ID,
"client_secret": PAYPAL_CLIENT_SECRET})
payment = paypal.Payment({
"intent": "sale",
"payer": {
"payment_method": "paypal" },
"redirect_urls": {
"return_url": "http://127.0.0.1:8000/ty",
"cancel_url": "http://127.0.0.1:8000/" },
"transactions": [ {
"item_list": {
"items": [{
"name": "membership",
"price": "2.00",
"currency": "GBP",
"quantity": 1 }]},
"amount": {
"total": "2.00",
"currency": "GBP" },
"description": "One of membership fee." } ] } )
redirect_url = ""
if payment.create():
print("Payment[%s] created successfully"%(payment.id))
for link in payment.links:
if link.method == "REDIRECT":
redirect_url = link.href
print("Redirect for approval: %s"%(redirect_url))
return self.redirect(redirect_url)
else:
print("Error while creating payment.")
print(payment.error)
response = payment.to_dict()
print response
payment = paypal.Payment.find(payment.id)
if payment.execute({"payer_id": response['payer_id']}):
print ("Payment executed successfully")
else:
print(payment.error) # Error Hash
print payment.to_dict()
print userData
So in the example at https://devtools-paypal.com/guide/pay_paypal/python?success=true&token=EC-8JL96732FP068791F&PayerID=QQGSRNHDACTLJ. Step 5 is not happening and no response is sent from PayPal?
This is Avi from PayPal here. I am not super familiar with Tornado, but after the line return self.redirect(redirect_url) happens in your code, and returns the user to the return_url, in payment.execute({"payer_id": response['payer_id']}) are you getting the payer_id correctly? Payer_id is returned appended to the return_url as one of the parameters in the format http://<return_url>?token=EC-60U79048BN7719609&PayerID=7E7MGXCWTTKK2. Also, what is the status of the payment after you execute payment = paypal.Payment.find(payment.id). The other suggestion I would have is to see if print payment.error prints a useful debug message and a debug_id which paypal merchant technical services can use to look at the issue.
You need other url where papypal redirects when the payment had been successful, where you will receive the token and the PayerID. In that GET method, you can put this part of the code (pseudocode):
payerid_param = request.get('PayerID')
payment = paypal.Payment.find(db_payment.id)
if payment.execute({"payer_id": payerid_param}):
print ("Payment executed successfully")
else:
print(payment.error) # Error Hash
You will need to save the payment_id between calls.
Why you use
return self.redirect(redirect_url)
I think you can use just
self.redirect(redirect_url)
I've never seen return statement in Tornado handlers.