Raw sql to json in Django, with Datetime and Decimal MySql columns - python

I am using Ajax to make some requests from client to server, I am using DJango and I have used some Raw Sql queries before, but all of my fields was Int, varchar and a Decimal, for the last one I had an enconding problem, but I overrided the "default" property of Json and everything worked.
But that was before, now I have a query wich gives me Decimal and DateTime fields, both of them gave me enconding errors, the overrided "default" doesn't work now, thats why with this new one I used DjangoJSONEncoder, but now I have another problem, and its not an encoding one, I am using dictfetchall(cursor) method, recomended on Django docs, to return a dictionary from the Sql query, because cursor.fetchall() gives me this error: 'tuple' object has no attribute '_meta'.
Before I just sended that dictionary to json.dumps(response_data,default=default) and everything was fine, but now for the encoding I have to use the following: json.dumps(response_data,cls=DjangoJSONEncoder) and if I send the dictionary in that way, I get this error:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
And if I try to use the serializers, like this:
response_data2= serializers.serialize('json', list(response_data))
And later send response_data2 to dumps, I get this error:
'dict' object has no attribute '_meta'
This is the code for the MySql query:
def consulta_sql_personalizada(nombres,apellidos,puesto):
from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("""select E.idEmpleado as id,CONCAT(Per.nombres_persona,' ',Per.apellidos_persona) as nombre,P.nombre_puesto as puesto,E.motivo_baja_empleado as motivo_baja,E.fecha_contratacion_empleado AS fecha_contratacion,E.fecha_baja_empleado as fecha_baja, SUM(V.total_venta) AS ventas_mes,E.fotografia_empleado as ruta_fotografia from Empleado as E
inner join Puesto as P on E.Puesto_idPuesto=P.idPuesto
inner join Venta as V on V.vendedor_venta=E.idEmpleado
inner join Persona as Per on E.Persona_idPersona=Per.idPersona
where (Per.nombres_persona like %s OR Per.apellidos_persona like %s OR E.Puesto_idPuesto=%s)
AND E.estado_empleado=1 AND V.estado_venta=1
AND
(YEAR(V.fecha_venta) = YEAR(Now())
AND MONTH(V.fecha_venta) = MONTH(Now()))""",[nombres,apellidos,puesto])
row = dictfetchall(cursor)
return row
And this is the last part of the view that makes the query and send it to ajax using json:
response_data=consulta_sql_personalizada(rec_nombres,rec_apellidos,rec_puesto)
return HttpResponse(
json.dumps(response_data,cls=DjangoJSONEncoder),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({"nothing to see": "this isn't happening"}),
content_type="application/json"
)
What I want to know is, how can I parse the raw sql result to Json using that enconding?

Sorry, was my bad, i'm using JQuery ajax method, and in the "success" part I forgot to stop using json.parse to print the data in the console, the data was json already, that's why I had that line 1 column 1 error. My code worked exactly like it was posted here. If someone want to know how to make asynchronous requests, I followed this tutorial: Django form submissions using ajax

Related

How to handle API responses(JSON) containing \x00 (or \u0000) in its data, and store the data in Postgres using django models?

I'm making an api call, and trying to store its response in Postgres using Django models.
Here's what I have been doing:
response = requests.post(url='some.url.com', data=json.dumps(data), headers={'some': 'header'})
response_data = json.loads(response.content.decode('utf-8'))
#handler is a object of a model
handler.api_response = response_data
handler.save()
But this used to fail, when my json had fields like 'field_name': '\x00\x00\x00\x00\x00'. It used to give following error :
DataError at /api/booking/reprice/
unsupported Unicode escape sequence
LINE 1: ... NULL, "api_status" = 0, "api_response" = '{"errorRe...
^
DETAIL: \u0000 cannot be converted to text.
CONTEXT: JSON data, line 1: ..."hoursConfirmed": 0, "field_name":...
How i tried to resolve this is by using the following:
response = requests.post(url='some.url.com', data=json.dumps(data), headers={'some': 'header'})
response_data = json.loads(response.content.decode('utf-8'))
#handler is a object of a model
handler.api_response = json.loads(json.dumps(response_data).encode("unicode-escape").decode())
handler.save()
The initial issue was solved then. But recently, when i got a field with value 'field2_name': 'Hey "Whats up"'. This thing failed by giving error:
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 1 column 143 (char 142)
Probably because json.loads() got confused with " inside the value as an enclosing " and not an escaped ".
Now, If i print the initial response just after json.loads(response.content.decode('utf-8')) statement, it shows the field as \x00\x00\x00\x00\x00.
But output of following code:
response = requests.post(url='some.url.com', data=json.dumps(data), headers={'some': 'header'})
response_data = json.loads(response.content.decode('utf-8'))
print(json.dumps(response_data))
This shows the field as \\u0000\\u0000\\u0000\\u0000\\u0000.
How does \x00 change to \\u0000
And how do i save this field into postgres tables ?
This is what i could think of.
json.loads(json.dumps(response_data).replace('\\u0000',''))
To add this statement before saving to postgres.
Is there a better way ?
Is the code response_data = json.loads(response.content.decode('utf-8')) wrong ? Or causing not to escape that particular character ?
FWIW, I recently ran into this and your proposed solution also worked for me. I think it's probably the simplest way to deal with it. Apparently this is the only character that can't go into a Postgres JSON column.
json.loads(json.dumps(response_data).replace('\\u0000',''))

Adding methods gives a 'index out of range error'?

When adding a vital component of methods=["POST", "GET"], my code gives the error:
Line 127, in PatientDashboard
""".format(Data[0][0]))
IndexError: list index out of range
I understand what this error normally means but I don't understand how adding methods affect the size of my list.
#app.route("/PatientDashboard.html", methods=["GET", "POST"])
def PatientDashboard():
Username = (request.args.get("Username"))
Connection = sqlite3.connect(DB)
Cursor = Connection.cursor()
Data = Cursor.execute("""
SELECT *
FROM PatientTable
WHERE Username = '{}'
""".format(Username))
Data = Data.fetchall()
AllAppointments = Cursor.execute("""
SELECT Title, Firstname, Surname, TimeSlot, Date, Status
FROM AppointmentTable
INNER JOIN DoctorTable ON AppointmentTable.DoctorID = DoctorTable.DoctorID
WHERE PatientID = '{}'
""".format(Data[0][0]))
AllAppointments = AllAppointments.fetchall()
The SQL statements work perfectly (database isn't empty) and when adding print(Data) after the first SQL statement there is an output of a nested list.
I have tried troubleshooting by looking at various other questions on stackoverflow but with no luck.
Thank you ever so much in advance.
EDIT 1:
Username = (request.args.get("Username"))
print("Username: ", Username)
Gives the correct output, e.g. Username: nx_prv but after using the POST request the output becomes Username: None.
EDIT 2:
I have managed to fix this using flask.sessions. The problem was that the request.args.get("Username") was getting 'reset' every time.
The scenario I envision: the route was tested with a GET method (because there was not methods argument), and everything was fine. The methods argument was added so a POST could be tested, and it "stopped working". But it really didn't stop working, it's just not built to handle a POST request.
From flask doc on request object the two salient attributes are:
form
A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but
instead in the files attribute.
args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
So a GET request will "populate" args and a POST request, form. Username will be None from this line Username = (request.args.get("Username")) on a POST request.
You can determine which method by interrogating the method attribute of the request object.
method
The current request method (POST, GET etc.)

Django valueError when using query_params

I am trying to setup an API using Django. In my views.py, I have this endpoint:
#api_view()
def update_label(request):
user_id = request.query_params['user_id']
date = datetime.strptime(request.query_params['date'], '%Y-%m-%dT%H:%M:%S.%f')
label_name = request.query_params['label_name']
value = request.query_params['value']
value = eval(value)
db_user_ctrl.update_label(date, user_id, label_name, value)
return Response({'status': 'SUCCESS'})
It updates some label in the database for some user. Multiple labels can be updated from this endpoint, some associate value with an integer, some associate value with a small dictionary e.g. {'item1':1,'item2':-1}. On the javascript side I use JSON.stringify(value) to format the value before sending it via a GET request. On the Django part, I can see the proper parameters have been recieved through the debugging interface. However I have the following error:
invalid literal for int() with base 10: '{"item1":-1}'
Associated with this line in my code:
value = request.query_params['value']
What is happening here? Why is he trying to casting the string into an integer?
EDIT 1:
Some more info on the stack trace:
.../venv/lib/python3.4/site-packages/django/core/handlers/base.py in get_response
.../venv/lib/python3.4/site-packages/django/core/handlers/base.py in get_response
.../venv/lib/python3.4/site-packages/django/views/decorators/csrf.py in wrapped_view
.../venv/lib/python3.4/site-packages/django/views/generic/base.py in view
.../venv/lib/python3.4/site-packages/rest_framework/views.py in dispatch
.../venv/lib/python3.4/site-packages/rest_framework/views.py in dispatch
.../venv/lib/python3.4/site-packages/rest_framework/decorators.py in handler
.../webapp/api/views.py in update_label
value = request.query_params['value']
Can you try
import json
json.loads(<query string value>)
The issue was quite sneaky, it was due to Gunicorn caching some files. In the old versions of views.py, I had value = int(request.query_params['value']). When I updated the code Gunicorn was still answering using the outdated cached files, hence the failure to cast a string into an int. I restarted Gunicorn and it's working now.

Error in query while inserting data using RDFlib to GraphDB

I parse a database into an RDFlib graph. I now want to INSERT the triples from this graph into the GraphDB triple store. The code works fine when I execute it on an older version of GraphDB-Lite hosted on Sesame. However, I get an error while executing the same query on the now standalone GraphDB 7.0.0. The graph is partially parsed before the error is raised and the inserted triples do show up in the triple store.
This is part of the code:
graphdb_url = 'http://my.ip.address.here:7200/repositories/Test3/statements'
##Insert into Sesame
for s,p,o in graph1:
pprint.pprint ((s,p,o))
queryStringUpload = 'INSERT DATA {%s %s %s}' %(s,p,o)
# queryStringUpload = 'DELETE WHERE {?s ?p ?o .}'
# print queryStringUpload
sparql = SPARQLWrapper(graphdb_url)
sparql.method = 'POST'
sparql.setQuery(queryStringUpload)
sparql.query()
Following is the error:
ARQLWrapper.SPARQLExceptions.QueryBadFormed: QueryBadFormed: a bad request has been sent to the endpoint, probably the sparql query is bad formed.
Response:
MALFORMED QUERY: Lexical error at line 1, column 93. Encountered: "/" (47), after : "purl.org"
What is causing the error and how do I resolve it?
It was a syntax error. I had URIs starting with http:/ instead of http:// in some places.

Flask - Get key values from request.get_json()

I am attempting to get the key values after requesting json data from ajax POST. I succesfully retrieve the data, however I get the error: " AttributeError: 'unicode' object has no attribute 'keys'".
I have attempted using json.load(data) however, this is also unsuccessful.
#app.route('/sendstats', methods=['GET', 'POST'])
#crossdomain(origin='*', headers='Content-Type')
def go():
data= request.get_json()
keys = sorted(data.keys())
.....
return "Search added"
Have you tried to use json.loads() (note the final s)?
When you set the request body in the first place, you might have put a unicode object there instead of str. this can happen for example if you call json.dumps twice on the same input (first time converts the dict to a str, second time converting it to unicode)

Categories

Resources