django rest framework nested fields with multiple models
This is django and django rest framework. I have 2 models: User and Phone.
first question:
I want to be able to update user data (email) as well as phone data (phone number) in 1 api update response. Phone numbers can be 0 or many. Well, it's actually like partial = True. If the user just wants to update the phone number then don't update the email and vice versa.
Additional Information: Phone is not included when registering. Just basic user information (last name, first name, email, password). After registration, the phone can only be updated in the user profile form. The user profile form is actually linked to multiple models i.e. "User and Phone"
second question:
How to serialize multiple phone_numbers and save to db?
class User(AbstractBaseUser):
email = models.EmailField(unique=True, default='')
USERNAME_FIELD = 'email'
class Phone(models.Model):
phone_number = models.CharField(max_length=10)
owner = models.ForeignKey(User)
--------------------------------------
class UserSerializer(serializers.ModelSerializer):
phone_number = PhoneSerializer(required=False, many=True)
class Meta:
model = User
fields = ('email, 'phone_number')
class PhoneSerializer(serializers.ModelSerializer):
class Meta:
Model = Phone
fields = ('phone_number')
The phone number field of the html form will have a plus sign to indicate that new phone numbers can be added. example is here
email : [email protected]
phone number: 23423432423
(add more)
phone number: 3423423423
(add more)
...
expected json
{
'email': '[email protected]',
'phone_number': '32432433223234'
}
or if many phone numbers are added
{
'email': '[email protected]',
'phone_number': '32432433223234',
'phone_number': '324342322342323'
}
perhaps
{
'email': '[email protected]',
'phone_number': ['32432433223234','324342322342323']
}
perhaps
{
'email': '[email protected]',
'Phone': [{'id': 1, 'phone_number': '32432433223234'}, {'id': 2, 'phone_number': '324342322342323'}]
}
Can this json be done? How does serializer and modelviewset do this? sorry i'm new to drf
- The default version for any nested objects.
You need to add serializer create
and update
method:
class UserSerializer(serializers.ModelSerializer):
phones = PhoneSerializer(required=False, many=True)
class Meta:
model = User
fields = ('email', 'phone_number')
def create(self, validated_data):
phones_data = validated_data.pop('phones', [])
user = super(UserSerializer, self).create(validated_data)
for phone_data in phones_data:
user.phone_set.create(phone_number=phone_data['phone_number'])
return user
def update(self, instance, validated_data):
phones_data = validated_data.pop('phones', [])
user = super(UserSerializer, self).update(instance, validated_data)
# delete old
user.phone_set.exclude(phone__in=[p['phone_number'] for p in phones_data]).delete()
# create new
for phone_data in phones_data:
user.phone_set.get_or_create(phone_number=phone_data['phone_number'])
return user
Application Creation:
{"email": "[email protected]" "phones": [{"phone_number": 12}, {"phone_number": 123}]}
Request an update:
{"phones": [{"phone_number": 22}]}
- Optimization of the current structure:
- Don't store phones as int fields - better strings.
- Accept calls as a list of strings, use
ListField
( http://www.django-rest-framework.org/api-guide/fields/#listfield ), handle create and update in serialize method.
renew
phones_data = validated_data.pop('phones')
->phones_data = validated_data.pop('phones', [])
, to handle the case of a call without a request.-
Should phone update and creation be done in modelviewset?
No, the serializer is responsible for the conversion
native data -> internal objects
. So if phone data is received, thePhoneNumber
object should be created.