This post is in continuation with “Writing class based Views in Django REST Framework” , for all related DRF posts, visit “Django REST Framework” page.
When we are working with creating JSON objects for users using API, sooner we realised that we are can push the data with same “userid” for multiple times, and problem with our existing post code was that it will always go on creating new entry for same userid, something like below,
{
"id": 2,
"userid": "my_userid",
"username": "lynxbee2",
"email": "social2(at)lynxbee.com",
"age": "56",
"useraddress": {
"id": 2,
"home_no": "124",
"street": "my home street",
"city": "my city",
"pincode": 123456
}
},
{
"id": 3,
"userid": "my_userid",
"username": "lynxbee30",
"email": "social(at)lynxbee.com",
"age": "4530",
"useraddress": {
"id": 3,
"home_no": "123",
"street": "my home street",
"city": "my city",
"pincode": 123456
}
},
but to note one thing here, is we can’t have only one user with same userid but have multiple entries like as above, even if we have multiple address, or email for same user, those can always be implemented with array of address’s or array of emails, but we can never have multiple entries of same “userid” in user database.
Hence, to avoid this we need to change our http post code from helloproject/helloapp/views.py as,
class user_by_uuid(APIView):
def post(self, request, user_id, format=None):
try :
user = UserInfo.objects.get(userid=user_id)
serializer = UserInfoSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except UserInfo.DoesNotExist :
serializer = UserInfoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
The import code in above is implementation of try and handling of exception as,
try :
user = UserInfo.objects.get(userid=user_id)
except UserInfo.DoesNotExist :
The above code, first tries to check if the user exists based on the user_id we passed in API, and if the user id doesn’t exits the control reaches to “except UserInfo.DoesNotExist” where we then create a new entry to the user. So, if the user_id already exists, we just save whatever we received from the data, so it act just like an edit.
Now, lets try to do http POST as,
$ curl -v -k -X POST -H "Accept: application/json" -H "Content-Type:application/json" -d '{"userid":"my_userid","username":"lynxbee1","email":"social(at)lynxbe":"45", "useraddress":{"home_no":"123","street":"my home street","city":"my city","pincode":"123456"}}' http://192.168.0.106:8001/user_by_id/my_userid/
So, when there was no userid with “my_userid” it created that JSON object and we got an reply with primary key = 30 as,
{"id": 30, "userid": "my_userid", "username": "lynxbee1", "email": "social(at)lynxbee.com", "age": "45", "useraddress": {"id": 30, "home_no": "123", "street": "my home street", "city": "my city", "pincode": 123456}}
Now, if we do the http POST with same “userid” as “my_userid” we will receive same primary key as 30.. which means its not creating any new entries with same userid instead our code just do edit of existing entries.
But still there is a problem.. ?????
in ideal case when someone use same userid in API and in payload then everything works fine, but as a developer people tends to make mistakes, and what if someone use different userid in API and payload, like if someone sent POST request as,
$ curl -v -k -X POST -H "Accept: application/json" -H "Content-Type:application/json" -d '{"userid":"my_incorrect_userid","username":"lynxbee1","email":"social(at)lynxbee.com","age":"45", "useraddress":{"home_no":"123","street":"my home street","city":"my city","pincode":"123456"}}' http://192.168.0.106:8001/user_by_id/my_userid/
in above request, as you can see, userid in API http://192.168.0.106:8001/user_by_id/my_userid/ is “my_userid” but in payload we passed wrong userid as “userid”:”my_incorrect_userid” .. in such case our above code fails, and we will still see the multiple entries of same userid i.e. “my_incorrect_userid” shown in dashboard..
Why this is so ?? because our below try code is satisfied once with correct userid so, we never go to catch and payload just gets saved multiple times for wrond userid.
Solution …
So, this can be corrected by checking in server, what is the userid in API and what is the userid in payload and if there any mismatch between two, we just report an error to client. Refer to “How to debug http GET / POST Requests and its data payloads in Django REST Framework ?”
So, after resolution of this error, the final post code looks like as below,
def post(self, request, user_id, format=None):
try :
#print(request.data)
userid_from_payload = request.data.get("userid", '')
#print(userid_from_payload)
userid_from_api = user_id
#print(userid_from_api)
if (userid_from_payload != userid_from_api) :
return JsonResponse({"status":"userid not matching...post error"}, status=status.HTTP_400_BAD_REQUEST)
user = UserInfo.objects.get(userid=user_id)
serializer = UserInfoSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except UserInfo.DoesNotExist :
serializer = UserInfoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)