Django JSon response format, nested fields - python

I just made an ajax request to a DJango View, it give me back the data, but i don't know how to get only the fields that i want.
This is the part of my view:
if request.method == 'POST':
txt_codigo_producto = request.POST.get('codigobarras_producto')
response_data = {}
resp_producto=Producto.objects.all().filter(codigobarras_producto=txt_codigo_producto)
resp_inventario=InventarioProducto.objects.all().filter(producto_codigo_producto__in=resp_producto).order_by('-idinventario_producto')[:1]
resp_precio=Precio.objects.all().filter(producto_codigo_producto__in=resp_producto,estado_precio=1).order_by('-idprecio')[:1] #
response_data['codprod']=serializers.serialize('json', list(resp_producto), fields=('codigo_producto'))
response_data['inventario']=serializers.serialize('json', list(resp_inventario), fields=('idinventario_producto'))
response_data['nombre']=serializers.serialize('json', list(resp_producto), fields=('nombre_producto'))
response_data['valorprod']=serializers.serialize('json', list(resp_precio), fields=('valor_precio'))
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
"json" is the name of the array that I get as response from the view, I send it to the console, as this:
console.log(JSON.stringify(json));
And i get this:
{"codprod":"[{\"model\": \"myapp.producto\", \"fields\": {}, \"pk\": 1}]",
"nombre":"[{\"model\": \"myapp.producto\", \"fields\": {\"nombre_producto\": \"Pantal\\u00f3n de lona \"}, \"pk\": 1}]",
"valorprod":"[{\"model\": \"myapp.precio\", \"fields\": {\"valor_precio\": \"250.00\"}, \"pk\": 1}]",
"inventario":"[{\"model\": \"myapp.inventarioproducto\", \"fields\": {}, \"pk\": 1}]"}
I tried this:
console.log(JSON.stringify(json.codprod));
With that I get this:
"[{\"model\": \"myapp.producto\", \"fields\": {}, \"pk\": 1}]"
But if I try something like json.codprod.pk or json.codprod[0] or json.codprod["pk] I get undefined in the console.
I want to know how to acces to those fields, in "valorprod" I want the "valor_precio" value, so it must be "250.00", in "nombre" I want the value of "nombre_producto" it must be "Pantal\u00f3n de lona".
Hope you can give me a hint. I think this is a JSON syntax problem, but I'm new with this.
Following Piyush S. Wanare and Roshan instructions, I have made some changes on the view:
resp_producto=Producto.objects.filter(codigobarras_producto=txt_codigo_producto)
resp_inventario=InventarioProducto.objects.filter(producto_codigo_producto__in=resp_producto).order_by('-idinventario_producto')[:1].only('idinventario_producto')
resp_precio=Precio.objects.filter(producto_codigo_producto__in=resp_producto,estado_precio=1).order_by('-idprecio')[:1].only('valor_precio')
resp_productonombre=Producto.objects.filter(codigobarras_producto=txt_codigo_producto).only('nombre_producto')
resp_productocodigo=Producto.objects.filter(codigobarras_producto=txt_codigo_producto).only('codigo_producto')
response_data = {'codprod': resp_productocodigo,'inventario':resp_inventario,'nombre':resp_productonombre,'valorprod':resp_precio}
return HttpResponse(
json.dumps(list(response_data)),
content_type="application/json"
)
But I get empty fields in the console:
["nombre","valorprod","codprod","inventario"]
Another edit, and the code that worked:
I used the views as they was at the beginning, with the double encoding, I just deleted the "codprod" part, but I wrote this on the ajax response code:
var res_valorprod=JSON.parse(json.valorprod);
var res_inventario=JSON.parse(json.inventario);
var res_nombre=JSON.parse(json.nombre);
var campos_valorprod =res_valorprod[0].fields;
var campos_nombre =res_nombre[0].fields;
console.log(res_nombre[0].pk);
console.log(campos_valorprod.valor_precio);
console.log(res_inventario[0].pk);
console.log(campos_nombre.nombre_producto);
This is working, I get what I want, but if you know something better to acces to the multiple nested JSON fields, I will be glad to know it. User dsgdfg gave me a hint.

You are doing multiple encoding, i.e. first you using serializers.serialize and then json.dumps.
Use only json.dumps and content_type as json like this, without using serializers.
response_dict = {'your_data_key': 'and your values'}
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
and then in client side you are not required to do JSON.stringify(json.codprod) .
As you sent content_type='application/json', it parse response as json.
console.log(resp.your_data_key); #will print proper response yor data values.

Answer to your first question:-
You can change your queries as follows:
resp_producto=Producto.objects.filter(codigobarras_producto=txt_codigo_producto).only('requiredField')
resp_inventario=InventarioProducto.objects.filter(producto_codigo_producto__in=resp_producto).only('requiredField').order_by('-idinventario_producto')[:1]
resp_precio=Precio.objects.filter(producto_codigo_producto__in=resp_producto,estado_precio=1).only('requiredField').order_by('-idprecio')[:1]
Then serialize it.
response_data['codprod']=serializers.serialize('json', list(resp_producto), fields=('codigo_producto'))
response_data['inventario']=serializers.serialize('json', list(resp_inventario), fields=('idinventario_producto'))
response_data['nombre']=serializers.serialize('json', list(resp_producto), fields=('nombre_producto'))
response_data['valorprod']=serializers.serialize('json', list(resp_precio), fields=('valor_precio'))
Suggestion:- It will be better if you create single {} by iterating through each required objects and create list [{},{}] rather than serializing it, and dump it as you have done like,
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
Then at FrontEnd you should use JSON.parse(responceData) for indexing over it.

Related

How to Post a List in Django Tests

I have a view which AJAX posts to with a list of items. I am attempting to add a test for this.
How can I post a list in a django test? I retrieve the data through this command:
listVar = request.POST.getlist('list[]')
I know this receives a list properly because I interface with Jquery and it returns the proper list, but how can I do this is python?
I have been trying code like this however printing 'listVar' always yields an empty list:
form = {"list": ["element 1", "element 2"]}
response = self.client.post('/viewurl/', form, follow=True)
Edit---
#Tomek suggested to drop the '[]', however that causes the python post request to work, but my ajax upload to return an empty list.
Here is a snippet of my ajax code:
$.ajax({
url: window.location.pathname,
method: 'POST',
data: {
list: a_list_I_create_elsewhere
},
...
Just drop the[] in the getlist argument.
def request_handler(request):
listVar = request.POST.getlist('list')
print(listVar)
should work
EDIT
Not to break compatibility with jQuery. I guess I'd test according to jQuery format
form = {"list[]": ["element 1", "element 2"]}
response = self.client.post('/viewurl/', form, follow=True)

How to parse jsonp returned from api using python

I'm very new to coding, and I'm building my first web application using open REST api with python flask.
I think the api is returning jsonp which looks like this - callbackfunction{ json }; and I get from other posts that all I need to do is getting rid of this padding. However, I can't figure out at which point I should implement the stripping.
This is my code. 5th line is throwing an error "the JSON object must be str, bytes or bytearray, not HTTPResponse"
def lookup(title):
try:
url = "http://www.aladin.co.kr/ttb/api/ItemSearch.aspx?ttbkey=foo&Query=bar"
result = urllib.request.urlopen(url)
data = json.loads(result)
data_json = data.split("{", 1)[1].strip("}")
return data_json
except requests.RequestException:
return None
I'm sure it's working well until 4th line. When I tried the code below, at least it returned result, though cryptic, like this.
b'{ "version" : "20070901", "title" :
"\xec\x95\x8c\xeb\x9d\xbc\xeb\x94\x98 \xea\xb2\x80 ...
"customerReviewRank":9 } ] };'
Judging by the keys, I'm pretty sure this is the information I requested. So what can I do to fix this? Thanks in advance!
def lookup(title):
try:
url = "http://www.aladin.co.kr/ttb/api/ItemSearch.aspx?ttbkey=foo&Query=bar"
result = urllib.request.urlopen(url)
res = result.readline()
return res

Passing multiple arguments in return 'Response' (python)

I am working in Angular and I am using Http Request and Response.
Is it possible to send multiple arguments in 'Response'.
Angular file:
this.http.get("api/agent/applicationaware").subscribe((data:any)...
python file:
def get(request):
...
return Response(serializer.data)
I want to send multiple arguments in the Response.
Like
return Response(serializer.data,obj.someothervalue)
can you help me with this?
Thanks in advance :)
You can return a dictionary
return Response({'serializer_data': serializer.data, 'some_other_value': obj.someothervalue})
Or you can append someothervalue to serializer.data
data = serializer.data
data['someothervalue'] = obj.someothervalue
return Response(data)
If obj.someothervalue is a dictionary as well, then you can merge two dictionaries:
data = serializer.data.copy()
data.update(obj.someothervalue)
return Response(data)
add a dictionary
dict = {}
dict['details'] = serializer.data
dict['other'] = someotherdata
return Response(dict)
hope this helps
You need to decide a protocol for API response first and then you can plan accordingly.
To answer your question, YES you can send multiple args in response.
You can create a dictionary/list and put all the values you want to send inside it. Now send that dictionary/list as your response.
I would recommend something kind of this :
response = dict()
response["data"] = dict()
response["data"]["serializer_data"] = serializer.data
response["data"]["some_other_value"] = obj.someothervalue
return Response(response)
On the receiving end of the response you will have to read the response data in similar way you sent it.

Django & Ajax: How can I create a csv file download from posting data through AJAX to Django?

I'm trying to allow the click trigger to do some backend dynamic csv creation, and then return it back to the user as a csv download file. I guess I'm not sure how I should write out the return statement other than just putting return response. I'v come across some other posts saying that I would need to set my url to a hidden iframe?? Not sure what this means though. Any tips?
Ajax looks like this:
$('#download-maxes').on('click', function(){
$.ajax({
type: "POST",
url: "{{request.path}}download/",
dataType: 'json',
async: false,
data: JSON.stringify(workouts),
success: function(workoutData) {
console.log(workoutData);
},
error:function(error){
console.log(error);
}
});
});
And my django view looks like this:
def download(request):
#(... a lot of mongo stuff here & other things defined)
workouts = json.load(request.body)
response = HttpResponse(content_type='text/xlsx')
response['Content-Disposition'] = 'attachment; filename="team_maxes.xlsx"'
writer = csv.writer(response)
writer.writerow(['Name', 'Date', 'Workout', 'Max'])
for member in team_members.all():
for wo in workouts:
wo_data = db.activity_types.find_one({"name": wo["name"]})
best_wo = db.activity.find_one({"u_id": member.user.id, "a_t": str(wo_data["_id"]), "is_last": 1}) or 0
member_name = member.user.first_name + ' ' + member.user.last_name
try:
max_stat = best_wo["y_ts"]
except:
max_stat = 0
try:
date = best_wo["e_d"]
except:
date = ""
workout_name = wo_data["name"]
writer.writerow([member_name, date, workout_name, max_stat])
return response
You don't need to use ajax. Since you are POSTing some json data to your view, just make a form with a hidden text input, and set it's value to the json data. Then make a regular submit button in the form.
When the form gets submitted, and the server responds with Content-Disposition: attachment; filename="team_maxes.xlsx", your browser will automatically trigger a download.
If you decide to go this route, Keep in mind:
You are using a regular html form now, with the POST method, so you must remember to use django's {% csrf_token %} tag inside of it.
You will probably have set the input's value to your json string, right before submitting the form.
Your workouts json gets sent in a form input. So, assuming you named your input "workouts", in your view you would do something like:
workouts = json.loads(request.POST.get('workouts'))
Plus a bunch of error checking, of course.

Python/Bottle/MongoDB: Unsupported response type: <type 'dict'>

#route('/locations', method='GET')
def get_location():
entity = db['locations'].find({'coordinate2d': {'$near': [37.871593, -122.272747]}}).limit(3)
if not entity:
abort(404, 'No nearby locations')
return entity
The response for the above portion of code is:
Error 500: Internal Server Error
Sorry, the requested URL 'http://localhost:8080/locations' caused an error:
Unsupported response type: <type 'dict'>
How can I grab that information from mongo as a type Bottle can return as JSON?
I got this error when I was trying to return a python list. I assumed it would translate into JSON, but it didn't. It made it to the line in bottle.py where it would handle iterables and found the first dict in the list and threw the error above.
To get around this, I simply embedded my list inside a dict.
return {'response': []}
The complete solution was a combination of transforming the db cursor to a list, manually setting the response type + custom encoding the return value
#route('/locations/:lat/:lng', method='GET')
def get_location(lat,lng):
response.content_type = 'application/json'
objdb = db.locations.find({'coordinate2d': {'$near': [lat,lng]}}, {'coordinate2d':bool(1)}).skip(0).limit(3)
entries = [entry for entry in objdb]
return MongoEncoder().encode(entries)
In my case, produces this:
[
{
"_id": "4f4201bb7e720d1dca000005",
"coordinate2d": [
33.02032100000006,
-117.19483074631853
]
},
{
"_id": "4f4201587e720d1dca000002",
"coordinate2d": [
33.158092999999994,
-117.350594
]
},
{
"_id": "4f42018b7e720d1dca000003",
"coordinate2d": [
33.195870000000006,
-117.379483
]
}
]
As per the doc mention on bottle http://bottlepy.org/docs/dev/ you have to return the string from the #route decorator. You have to return the template with data or string.
If you want to generate the json then you have to change the Content-Type.
Dictionaries
As mentioned above, Python dictionaries (or subclasses
thereof) are automatically transformed into JSON strings and returned
to the browser with the Content-Type header set to application/json.
This makes it easy to implement json-based APIs. Data formats other
than json are supported too. See the tutorial-output-filter to learn
more.
http://bottlepy.org/docs/dev/tutorial.html?highlight=json#generating-content

Categories

Resources