In our previous post “Understanding many-to-one relationship and implementing it using ForeignKey in Django / DRF” we showed how you can create a JSON object (useraddress) and add it in another main JSON object, so in our previous post we created a JSON structure 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
}
}
]
Now, what will happen if our users have more than one address, in this case we can’t use above JSON structure hence using “Many-To-One” implementation using ForeignKey will not work, so we need to extend this JSON to create an array of address’s .. this is called as “many-to-many” relationship implementation.
So, our plan is to design an JSON which should look 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
},
{
"id": 2,
"home_no": "01",
"street": "my 01 home at street",
"city": "my current city",
"pincode": 999999
}
]
}
So, as you can see we want the user to have more than one address i.e. array of address’s . This can be achieved by changing “models.ForeignKey” to “models.ManyToManyField” in our previous’s posts code. So, the code changes in models.py would required as,
Remove
- useraddress = models.ForeignKey('UserAddress', on_delete=models.CASCADE)
and add
+ useraddress = models.ManyToManyField('UserAddress')
And also we need to change the serializers.py for our application as, i.e change UserAddressSerializer() to UserAddressSerializer(many=True)
- useraddress = UserAddressSerializer()
+ useraddress = UserAddressSerializer(many=True)
So, the total changes required in our code would be as below,
$ git diff
diff --git a/helloproject/helloapp/models.py b/helloproject/helloapp/models.py
index 2d6cc34..500f229 100644
--- a/helloproject/helloapp/models.py
+++ b/helloproject/helloapp/models.py
@@ -15,7 +15,7 @@ class UserInfo (models.Model) :
email = models.CharField(max_length=100)
age = models.CharField(max_length=100)
- useraddress = models.ForeignKey('UserAddress', on_delete=models.CASCADE)
+ useraddress = models.ManyToManyField('UserAddress')
class Meta:
ordering = ['id']
diff --git a/helloproject/helloapp/serializers.py b/helloproject/helloapp/serializers.py
index 6f92f25..29874cf 100644
--- a/helloproject/helloapp/serializers.py
+++ b/helloproject/helloapp/serializers.py
@@ -9,7 +9,7 @@ class UserAddressSerializer(serializers.ModelSerializer):
fields = ['id', 'home_no', 'street', 'city', 'pincode']
class UserInfoSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
- useraddress = UserAddressSerializer()
+ useraddress = UserAddressSerializer(many=True)
class Meta:
model = UserInfo
So, our final code in actual models.py and serializers.py would be as below,
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.ManyToManyField('UserAddress')
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(many=True)
class Meta:
model = UserInfo
fields = ['id', 'userid', 'username', 'email', 'age', 'useraddress']
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
second_home_no=01
second_street="my 01 home at street"
second_city="my current city"
second_pincode=999999
address="[{\"home_no\":\"$home_no\",\"street\":\"$street\",\"city\":\"$city\",\"pincode\":\"$pincode\"},{\"home_no\":\"$second_home_no\",\"street\":\"$second_street\",\"city\":\"$second_city\",\"pincode\":\"$second_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_class_based_views