I have a question about dealing with m2m / through models and their presentation in django rest framework. Let's take a classic example:
models.py:
from django.db import models
class Member(models.Model):
name = models.CharField(max_length = 20)
groups = models.ManyToManyField('Group', through = 'Membership')
class Group(models.Model):
name = models.CharField(max_length = 20)
class Membership(models.Model):
member = models.ForeignKey('Member')
group = models.ForeignKey('Group')
join_date = models.DateTimeField()
serializers.py:
imports...
class MemberSerializer(ModelSerializer):
class Meta:
model = Member
class GroupSerializer(ModelSerializer):
class Meta:
model = Group
views.py:
imports...
class MemberViewSet(ModelViewSet):
queryset = Member.objects.all()
serializer_class = MemberSerializer
class GroupViewSet(ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
When GETing an instance of Member, I successfully receive all of the member's fields and also its groups - however I only get the groups' details, without extra details that comes from the Membership model.
In other words I expect to receive:
{
'id' : 2,
'name' : 'some member',
'groups' : [
{
'id' : 55,
'name' : 'group 1'
'join_date' : 34151564
},
{
'id' : 56,
'name' : 'group 2'
'join_date' : 11200299
}
]
}
Note the join_date.
I have tried oh so many solutions, including of course Django Rest-Framework official page about it and no one seems to give a proper plain answer about it - what do I need to do to include these extra fields? I found it more straight-forward with django-tastypie but had some other problems and prefer rest-framework.
NOTE: As a Software Engineer, I love to use Architectures and I have deeply worked on Layered Approach for Development so I am gonna be Answering it with Respect to Tiers.
As i understood the Issue, Here's the Solution models.py
serializers.py
CustomModels.py
BusinessLogic.py
You would technically, have to pass the Request to DataAccessLayer which would return the Filtered Objects from Data Access Layer but as I have to Answer the Question in a Fast Manner so i adjusted the Code in Business Logic Layer!
I was facing this problem and my solution (using DRF 3.6) was to use SerializerMethodField on the object and explicitly query the Membership table like so:
This will return a list of dicts for the groups key where each dict is serialized from the MembershipSerializer. To make it writable, you can define your own create/update method inside the MemberSerializer where you iterate over the input data and explicitly create or update Membership model instances.
How about.....
On your MemberSerializer, define a field on it like:
and then on your membership serializer you can create this:
That has the overall effect of creating a serialized value, groups, that has as its source the membership you want, and then it uses a custom serializer to pull out the bits you want to display.
EDIT: as commented by @bryanph,
serializers.field
was renamed toserializers.ReadOnlyField
in DRF 3.0, so this should read:for any modern implementations