Anuj TBE
Anuj TBE

Reputation: 9796

Django REST Framework : serializer fields are missing in the response

I'm using Django 2.0 and Django REST Framework.

I have two models contact and transaction as below

contact model

class Contact(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100, blank=True, null=True)

amount given model

class AmountGiven(models.Model):
    contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
    amount = models.FloatField(help_text='Amount given to the contact')
    interest_rate = models.FloatField(blank=True, default=None, null=True, help_text='% of interest to be calculated')
    _given_date = models.DateTimeField(
        db_column='given_date',
        default=timezone.now,
        help_text='Date and time when amount was given to the contact'
    )

    def __str__(self):
        return str(self.amount)

    @property
    def given_date(self):
        return self._given_date

    @given_date.setter
    def given_date(self, value):
        self._given_date = value

    @property
    def interest_to_pay(self):
        if self.interest_rate:    
            datetime_diff = datetime.now(get_localzone()) - self.given_date
            days = datetime_diff.days
            duration_in_year = days/365

            simple_interest_amount = (self.amount * duration_in_year * self.interest_rate)/100

            return simple_interest_amount

        return 0

    @property
    def total_payable(self):
        return self.amount + self.interest_to_pay

    @property
    def amount_due(self):
        returned_amount = 0
        for returned in self.amountreturned_set.all():
            returned_amount += returned.amount

        return self.total_payable - returned_amount

and ContactSerializer

class ContactSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedRelatedField(
        view_name='contacts:detail',
        read_only=True
    )

    user = serializers.CurrentUserDefault()

    amount_due = ReadOnlyField(source='amountgiven__amount_due')

    class Meta:
        model = Contact
        fields = ('url', 'id', 'first_name', 'last_name', 'full_name', 'amount_due')

and in views.py

class ContactViewSet(viewsets.ModelViewSet):
    serializer_class = ContactSerializer
    permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)

    def get_queryset(self):
        return Contact.objects.filter(user=self.request.user)

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

But there is no field as amount_due and url in the response returned while making the request to /contacts/ endpoint with GET method.

Upvotes: 0

Views: 3001

Answers (2)

Ehsan Nouri
Ehsan Nouri

Reputation: 2040

Based on your comment, you want the sum of all the amounts(please edit your question). so you should use annotate in your queryset:

from django.db.models import Sum

def get_queryset(self):
    return Contact.objects.filter(user=self.request.user).annotate(amount_due=Sum('amountgiven_set__amount'))

(I recommend using modelManager for the queryset and the filtering instead of doing it here)

and add a field like this to your serializer:

amount_due = serializer.IntegerFiled()

Upvotes: 2

Enthusiast Martin
Enthusiast Martin

Reputation: 3091

Your modeling doesn't allow you to access amount_due in the way which you'd like.

Your Contact model does not have amountgiven attribute. It does however have amountgiven_set which you can use to obtain a queryset of amountgiven for given contact.

But there can be multiple ones so you need to decide which amount_due you want to display in your serializer.

You can use SerializerMethodField to serializer the value of amount_due which you would like:

class ContactSerializer(serializers.HyperlinkedModelSerializer):
    amount_due = serializers.SerializerMethodField()

    def get_amount_due(self, obj):
         amountgiven = obj.amountgiven_set.first()
         return amountgiven.amount_due

But again, as i already mentioned - amountgiven_set returns a queryset where you can have multiple objects.

In case you are sure you have only one for given contact, you can use first() as in my example to get it.

Upvotes: 0

Related Questions