Water has been taken for granted. - Jan Eliasson
DRF's Serializer has been proved to be a killing feature.
Here I am going to share details of updating a Foreign key object data while updating a reverse relation object using serializer.
The point here is that, while we usually use foreign key fields in the serializer for reading operation, we can also use them to write operations.
Update FK object data:
Let's consider a scenario.
Where we have an account, to which loan applications can be submitted. While approving an application, we need to collect the approved_amount
and reason
.
class Account(models.Model):
account_number = models.CharField(max_length=255)
approved_amount = models.PositiveIntegerField(default=0)
reason = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.account_number
class LoanApplication(models.Model):
class Status(models.TextChoices):
SUBMITTED = 'SUBMITTED', 'Submitted',
REJECTED = 'REJECTED', 'Rejected'
APPROVED = 'APPROVED', 'Approved'
account = models.ForeignKey(Account, on_delete=models.CASCADE)
status = models.CharField(
max_length=255, choices=Status.choices, default=Status.SUBMITTED)
def __str__(self):
return str(self.account)
The above requirement shall be done using only one API call.
As shown in the above code shots, we have approved_amount
and reason
in the Account
model, whereas approval shall be done to the LoanApplication
object.
Let's see how the serializer tackles the above problem.
As in the below shots, while approval, we collect the amount and reason in the same API. In serializer, just before updating LoanApplication
, we separate Account
data and update to the appropriate account, then proceed to update the loan application.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
class LoanApplicationSerializer(serializers.ModelSerializer):
approved_amount = serializers.IntegerField(
source='account.approved_amount')
reason = serializers.CharField(source='account.reason')
class Meta:
model = LoanApplication
exclude = ('account',)
def update(self, instance, validated_data):
account_data = validated_data.pop('account', None)
if account_data:
account_serializer = AccountSerializer(
instance.account, data=account_data, partial=True)
account_serializer.is_valid(raise_exception=True)
account_serializer.save()
return super().update(instance, validated_data)
Top comments (0)