Serializing data in Django Rest Framework for custom fields

2,439 views
Skip to first unread message

arjun....@zapprx.com

unread,
Aug 24, 2015, 10:33:18 AM8/24/15
to Django REST framework
Had a certain query regarding a certain implementation.Please do let me know if this is not the right forum...

My models.py is as follows:

class Prescription(models.Model):
    pr_id = models.CharField()
    date_prescribed = models.DateTimeField()
    doctor = models.ForeignKey('Doctor')
    pharmacy = models.ForeignKey('Pharmacy')  

class Doctor(models.Model):
    name = models.CharField()
    age = models.IntegerField()

class Pharmacy(models.Model):
    name = models.CharField()
    status = models.CharField()

Now i need to get the count of all pr_id grouped by month starting from this month and going back 6 months.This data needs to be in json as it needs to be sent to Angular to render a line chart. My views.py is as follows:

class PrescriptionTrendListView(generics.ListAPIView):
    end_date = datetime.utcnow().date()
    start_date = end_date + relativedelta(months=-6)    
    queryset = (Prescription.objects.extra(select={'month': connection.ops.date_trunc_sql('month', 'date_prescribed')})
                            .filter(date_prescribed__range=(start_date,end_date))
                            .values('month')
                            .annotate(Count('pr_id'))
                            .order_by('month'))
    serializer_class = LineGraphSerializer

The queryset works because I tried it in the shell and it gives me the correct data as follows:

>>> queryset
[{'pr_id__count': 16, 'month': datetime.datetime(2015, 2, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 71, 'month': datetime.datetime(2015, 3, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 75, 'month': datetime.datetime(2015, 4, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 96, 'month': datetime.datetime(2015, 5, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 99, 'month': datetime.datetime(2015, 6, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 93, 'month': datetime.datetime(2015, 7, 1, 0, 0, tzinfo=<UTC>)}, 
 {'pr_id__count': 39, 'month': datetime.datetime(2015, 8, 1, 0, 0, tzinfo=<UTC>)}]

However,I am not sure how to create the LineGraphSerializer. The two fields that the queryset gives are the count of the Ids and the months which are not in the initial model.Would you have any idea as to how would I go about creating this file.Any help will be greatly appreciated.

Regards,

Arjun

Chris Foresman

unread,
Aug 24, 2015, 2:53:34 PM8/24/15
to Django REST framework
I'd do something like:

class LineGraphSerializer(serializers.Serializer):
    count
= serializers.IntegerField(source='pr_id__count')
    month
= serializers.SerializerMethodField()


   
def get_month(self, obj):
       
return '{0}-{1}'.format(obj.month.year, obj.month.month)

You might need to play with that a bit to get it right (will obj be a dict or object, I'm not sure...), but I think that's on the right track.

Arjun Nambiar

unread,
Aug 24, 2015, 4:01:23 PM8/24/15
to django-res...@googlegroups.com
Looks promising..will give that a shot..thanks..

--
You received this message because you are subscribed to a topic in the Google Groups "Django REST framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-rest-framework/wkge9i0PKNI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-rest-fram...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Regards,
Arjun

arjun....@zapprx.com

unread,
Aug 24, 2015, 5:03:15 PM8/24/15
to Django REST framework
So this is what my final code looks like :

models.py

class Prescription(models.Model):
    date_prescribed = models.DateTimeField()
    doctor = models.ForeignKey(Doctor)
    pharmacy = models.ForeignKey(Pharmacy)  

class Doctor(models.Model):
    name = models.CharField()
    age = models.IntegerField()

class Pharmacy(models.Model):
    name = models.CharField()
    status = models.CharField()

views.py

class PrescriptionTrendListView(generics.ListAPIView):
    queryset = Prescription.objects.all()
    serializer_class = LineGraphSerializer

    def get_queryset(self):
        end_date = timezone.now()
        start_date = end_date - relativedelta(months=6)
        truncate_date = connection.ops.date_trunc_sql('month', 'date_prescribed')
        qs = super(PrescriptionTrendListView,self).get_queryset.extra(select={'month': truncate_date})
        return qs.filter(date_prescribed__range=(start_date, end_date)).annotate(pk_count=Count('pk')).order_by('month'

and my serializer.py

from rest_framework import serializers
from .models.Prescription import Prescription

class LineGraphSerializer(serializers.ModelSerializer):
    pk_count = serializers.IntegerField(read_only=True)
    month = serializers.DateTimeField(read_only=True)

    class Meta:
    	model = Prescription
    	fields = ['pk_count', 'month']

    

However this gives an error stating NoneType object is not iterable.Full traceback here .. Any help ??
To unsubscribe from this group and all its topics, send an email to django-rest-framework+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Regards,
Arjun

Tymur Maryokhin

unread,
Aug 24, 2015, 6:14:43 PM8/24/15
to Django REST framework
Upon reading the documentation http://www.django-rest-framework.org/api-guide/serializers/#read-only-baseserializer-classes:

class LineGraphSerializer(serializers.BaseSerializer):
   
def to_representation(self, obj):
       
return {
           
'pk_count': obj['pk_count'],
           
'month': obj['month']
       
}

And don't forget to define the get method in the viewset to pass the data as a list of dictionaries:

def get(self, request, *args, **kwargs):
    graph_data
= self.get_queryset().values('pk_count', 'month')
    serializer
= self.get_serializer(data=graph_data, many=True)
   
return Response(serializer.data)

No guarantee that this 100% works, but probably closer to what you want.

понедельник, 24 августа 2015 г., 23:03:15 UTC+2 пользователь arjun....@zapprx.com написал:

arjun....@zapprx.com

unread,
Aug 24, 2015, 11:02:36 PM8/24/15
to Django REST framework
Hi Tymur,

Thanks for that..but still no luck..get the same error..
...

Chris Foresman

unread,
Aug 24, 2015, 11:39:21 PM8/24/15
to django-res...@googlegroups.com
Are you calling is_valid()? In your view, try then printing serializer.validated_data and see what gets returned. 
--
You received this message because you are subscribed to a topic in the Google Groups "Django REST framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-rest-framework/wkge9i0PKNI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-rest-fram...@googlegroups.com.

Arjun Nambiar

unread,
Aug 24, 2015, 11:50:31 PM8/24/15
to django-res...@googlegroups.com
Chris,

Pardon my ignorance..but how would i do that ?
--
Regards,
Arjun

Chris Foresman

unread,
Aug 25, 2015, 12:43:40 AM8/25/15
to django-res...@googlegroups.com
I think someone recommended the following:
```python
def get(self, request, *args, **kwargs):
    graph_data = self.get_queryset().values('pk_count', 'month')
    serializer = self.get_serializer(data=graph_data, many=True)
    return Response(serializer.data)
```

I’d recommend amending that as follows:
```python
def get(self, request, *args, **kwargs):
    graph_data = self.get_queryset().values('pk_count', 'month')
    serializer = self.get_serializer(graph_data, many=True)
    serializer.is_valid()
    print graph_data
    print serializer.validated_data
    return Response(serializer.data)
```

First, pass the results of your queryset as objects, not data. Calling is_valid() causes serialization to happen. Printing graph_data tells us what, if anything, was passed into the serializer. Printing validated_data will tell us if we were able to serialize the specific data we want from the queryset.


Chris Foresman


arjun....@zapprx.com

unread,
Aug 25, 2015, 2:09:32 AM8/25/15
to Django REST framework
Ok..i did that and the new error stated that LineGraphSerializer' object has no attribute 'base_fields'.
I am on DRF 2.4.6 and looks like BaseSerializer was introduced only in 3.0 :-(
Chris Foresman



To unsubscribe from this group and all its topics, send an email to django-rest-framework+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Django REST framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-rest-framework/wkge9i0PKNI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-rest-framework+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Regards,
Arjun

--
...
Reply all
Reply to author
Forward
0 new messages