I am attempting to build a REST API in Django for a Google Spreadsheet with Gspread, I'm running into a lot of issues (so if anyone happens to have a full example lying around, feel free to share... please? :)). One of those issues it that I'm trying to receive JSON for a POST request (and later on other requests, of course). This is, however, failing. This is my code:
view.py (I'm aware that that IF-statement is not how it works
elif request.method == 'POST':
received_json_data = json.loads(request.body.decode("utf-8"))
content = received_json_data['content']
if content != "":
worksheet.insert_row([content["date"], content["days"], content["firstname"], content["lastname"], content["team"], content["training"], content["company"], content["city"], content["cost"], content["invoice"], content["info"]], 1)
return JsonResponse(content, safe=False, status=status.HTTP_201_CREATED)
else:
return JsonResponse([], safe=False, status=status.HTTP_400_BAD_REQUEST)
A test that has been written for this:
def test_post_all_training_returns_201_when_correct_format(self):
"""
A POST request on /trainings/ should create a new training
"""
headers = {'content-type': 'application/json'}
response = self.client.post('/trainings/', json=json.dumps(self.training_json_body), headers=headers, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
The contents of the training_json_body:
self.training_json_body = {
"date": "1/1/2018",
"days": 1,
"firstname": "Data",
"lastname": "Data",
"team": "Data",
"training": "Data",
"company": "Data",
"city": "Data",
"cost": 1,
"invoice": "Data",
"info": "Data"
}
Traceback
Traceback (most recent call last):
File "C:\Python\backend\unleashedapp\trainings\tests.py", line 64, in test_post_all_training_returns_201_when_correct_format
response = self.client.post('/trainings/', json=json.dumps(self.training_json_body), headers=headers, format="json")
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\test\client.py", line 525, in post
response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\test\client.py", line 341, in post
secure=secure, **extra)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\test\client.py", line 404, in generic
return self.request(**r)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\test\client.py", line 485, in request
raise exc_value
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\exception.py", line 35, in inner
response = get_response(request)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Python\backend\unleashedapp\trainings\views.py", line 36, in training_list
received_json_data = json.loads(request.body.decode("utf-8"))
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\json\__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\yanni\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I have searched for a solution for a couple of days now but can't get it to work, so I would be really greatful if someone could push me in the right direction.
I have updated my code to the following:
class TrainingList(APIView):
def post(self, request, format=None):
sheet = request.GET.get('sheet', 'Data')
worksheet = spreadsheet.worksheet(sheet)
worksheet.append_row([request.data.get("date"), request.data.get("days"), request.data.get("firstname"), request.data.get("lastname"), request.data.get("team"), request.data.get("training"), request.data.get("company"), request.data.get("city"), request.data.get("cost"), request.data.get("invoice"), request.data.get("info")])
return JsonResponse("[]", safe=False, status=status.HTTP_201_CREATED)
This no longer throws any errors, but append_row() function is now adding "None" for every field, so clearly the data is still not going through. How can I fix this?
If you are using Django REST framework then you can easily get the data from the request object by accessing the request.data
dictionary (more info here).
If you are using a vanilla Django view then you can access POST data by using the request object and accessing request.POST['<field_name>']
or request.POST.get('<field_name>')
.
For example:
request.POST.get("date")
You can read more about that or look at examples here.