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.

Command line execution

Terminalbash
sed 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

Risk level: destructive. Review the command before running it.

Implementation details

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

Gotchas and common issues

  • Permission checks - verify user access rights and sudo privileges before executing system-level operations.

  • Environment configuration - double-check path variables and dependency versions to prevent runtime failures.

  • Backup safeguards - maintain configuration backups before applying system or database modifications.

Following these steps ensures clean configuration and reliable execution for implement writable nested model serializer (json object in another json object) for django rest framework.