0

I have 2 models connected via M2M model:

class Person(models.Model):
    name = models.CharField(max_length=30)

class Group(models.Model):
    name = models.CharField(max_length=100)
    members = models.ManyToManyField(Person, through='GroupPerson', related_name='groups')

class GroupPerson(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    rank = models.CharField(max_length=100', default='New')

and serializers

class GroupPersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = GroupPerson
        fields = '__all__'

class GroupSerializer(serializers.ModelSerializer):
    members = serializers.PrimaryKeyRelatedField(many=True, queryset=Person.objects.all())

    class Meta:
        model = Group
        fields = '__all__'


class PersonSerializer(serializers.ModelSerializer):
    groups = serializers.PrimaryKeyRelatedField(many=True, queryset=Group.objects.all())

    class Meta:
        model = Person
        fields = '__all__'

And API go get a group returns

[
  {
    "name": "...",
    "members": [ 1, ... ]
  }
]

How do I get a response something like following:

[
  {
    "name": "...",
    "members": [
      {
        "group_id": 1,
        "person_id": 1,
        "rank": "New"
      },
      ...
    ]
  }
]

I.e., I want to GET/POST/PATCH all fields of the through relation

Sourabh
  • 21
  • 4

2 Answers2

0

Instead of using

    groups = serializers.PrimaryKeyRelatedField(many=True, queryset=Group.objects.all())

Do

    groups = GroupSerializer(many=True, read_only=True)

This will allow DRF to serialize groups as a list of nested objects. For more details, check out the documentation for Nested Relationships

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • I don't want to serialize `Group`. That won't give me the field `rank` field in `GroupPerson`. I want to serialize `GroupPerson`. But if I use GroupPersonSerializer, I get error `Got AttributeError when attempting to get a value for field...` – Sourabh May 18 '21 at 15:37
  • @Sourabh OIC...you want the id for the group and then the rank. Probably use `GroupPersonSerializer` instead of `GroupSerializer` as I did in my answer. – Code-Apprentice May 18 '21 at 15:40
  • Doesn't work for me. I get this: Got AttributeError when attempting to get a value for field `group` on serializer `GroupPersonSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Person` instance. Original exception text was: 'Person' object has no attribute 'group'. – Sourabh May 19 '21 at 07:27
  • @Sourabh I suggest you post a new question to show your current code. – Code-Apprentice May 27 '21 at 15:34
0

Try:

class PersonSerializer(serializers.ModelSerializer):
    groups = serializers.SerializerMethodField()

    def get_groups(self, person):
        queryset = GroupPerson.objects.filter(person=person)
        return GroupPersonSerializer(queryset, many=True).data

    class Meta:
        model = Person
        fields = ["id", "name", "groups"]
Ashraful Islam
  • 546
  • 2
  • 8
  • Doesn't work for me. I get this: Got AttributeError when attempting to get a value for field `group` on serializer `GroupPersonSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Person` instance. Original exception text was: 'Person' object has no attribute 'group'. – Sourabh May 19 '21 at 07:26
  • You can try now. – Ashraful Islam May 19 '21 at 10:15