As we mentioned in the title of this post, the purpose of this post is to demonestrate how we can Django REST Framework API which works with payload JSON which contains one object (e.g. useraddress) inside another Json object like as below,
[
{
"id": 1,
"userid": "my_userid",
"username": "lynxbee1",
"email": "social(at)lynxbee.com",
"age": "47",
"useraddress": {
"id": 1,
"home_no": "123",
"street": "my home street",
"city": "my city",
"pincode": 123456
}
}
]
This post is in continuation with our another post “Developing REST API using functions in DRF application views” which shows how you can use function based views to implement REST API. In this post, we will just modify same codebase,
In our post we had implemented code which used only one single JSON object like below,
[{
"id": 1,
"userid": "my_userid",
"username": "lynxbee1",
"email": "social(at) lynxbee.com",
"age": "47"
}]
Now, in this we post, as we can see in initial JSON, we want one more JSON object “useraddress” in this outer Json object which represent single user., so lets see how this can be done
vim helloproject/helloapp/models.py
from django.db import models
class UserAddress(models.Model) :
home_no = models.CharField(max_length=100)
street = models.CharField(max_length=100)
city = models.CharField(max_length=100)
pincode = models.IntegerField()
def __str__(self) :
return self.home_no
class UserInfo (models.Model) :
userid = models.CharField(max_length=100)
username = models.CharField(max_length=100)
email = models.CharField(max_length=100)
age = models.CharField(max_length=100)
useraddress = models.ForeignKey('UserAddress', on_delete=models.CASCADE)
def __str__(self) :
return self.username
As you can see in above code, we defined class “UserAddress” which will achieve the “useraddress” json object dependent tables and then we referenced this class from original “UserInfo” class, so the actual code address compared to previous code was as,
+class UserAddress(models.Model) :
+ home_no = models.CharField(max_length=100)
+ street = models.CharField(max_length=100)
+ city = models.CharField(max_length=100)
+ pincode = models.IntegerField()
+
+ def __str__(self) :
+ return self.home_no
+
class UserInfo (models.Model) :
+ useraddress = models.ForeignKey('UserAddress', on_delete=models.CASCADE)
+
def __str__(self) :
return self.username
Next now, we need to change the serializers.py for our app, as below,
vim helloproject/helloapp/serializers.py
from rest_framework import serializers
from helloproject.helloapp.models import UserInfo, UserAddress
from drf_writable_nested import WritableNestedModelSerializer
class UserAddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = ['id', 'home_no', 'street', 'city', 'pincode']
class UserInfoSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
useraddress = UserAddressSerializer()
class Meta:
model = UserInfo
fields = ['id', 'userid', 'username', 'email', 'age', 'useraddress']
As you can see above, we created totally new “UserAddressSerializer” class and have referenced this “UserAddressSerializer” class as a variable “useraddress” inside UserInfoSerializer and then same variable we appended at last to fields.
Hence the actual code which we added / changed was like below,
+from helloproject.helloapp.models import UserInfo, UserAddress
+
+from drf_writable_nested import WritableNestedModelSerializer
+
+class UserAddressSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = UserAddress
+ fields = ['id', 'home_no', 'street', 'city', 'pincode']
+
+class UserInfoSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
+ useraddress = UserAddressSerializer()
-class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = UserInfo
- fields = ('id', 'userid', 'username', 'email', 'age')
+ fields = ['id', 'userid', 'username', 'email', 'age', 'useraddress']
Notice here, apart from just creating one more “UserAddressSerializer” and linking it with “UserInfoSerializer” we have also changed UserInfoSerializer as below, with additional argument WritableNestedModelSerializer,
-class UserInfoSerializer(serializers.ModelSerializer):
+class UserInfoSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
The reason for this has been explained in our another post, “Solved : The .create() method does not support writable nested fields by default.”
Now start the server as,
$ vim run_server.sh
#!/bin/bash
SERVER_IP="192.168.0.106"
SERVER_PORT="8000"
python3 -m venv env
source env/bin/activate
pip install django
pip install djangorestframework
pip install drf_writable_nested
python manage.py makemigrations
python manage.py migrate --run-syncdb
python manage.py migrate
python manage.py runserver $SERVER_IP:$SERVER_PORT
$ bash run_server.sh
Once the server is running from another shell, lets try to push the nested JSON as payload,
$ vim http_post.sh
#!/bin/bash
API_URL="http://192.168.0.106:8000/users"
userid="my_userid"
username="lynxbee1"
email="social(at)lynxbee.com"
age="45"
home_no=123
street="my home street"
city="my city"
pincode=123456
address="{\"home_no\":\"$home_no\",\"street\":\"$street\",\"city\":\"$city\",\"pincode\":\"$pincode\"}"
data="{\"userid\":\"$userid\",\"username\":\"$username\",\"email\":\"$email\",\"age\":\"$age\", \"useraddress\":"$address"}"
echo $data
#exit
curl -v -k -X POST -H "\"Accept: application/json\"" -H "\"Content-Type:application/json\"" -d $data "$API_URL/"
$ bash http_post.sh
And now when you see the JSON in django dashboard at http://192.168.0.106:8000/users/ you should see the JSON with another object inside main object as required and mentioned at beginning of the post.
You can download complete source from github at https://github.com/lynxbee/drf_api_view_with_function.git