[Django]-DRF 3 – Creating Many-to-Many update/create serializer with though table

25👍

I have no clue if there is an easier way, but the only way I managed to get this to work is to reference the ‘through’ model “memberships” in the Group serializer and write custom code for .create() and .update(). This seems like a lot of work to just set M2M FK’s. If someone knows a better way I’d love to hear it.

class GroupMembershipSerializer(ModelSerializer):
    class Meta:
        model = Membership
        fields = ('person',)

class GroupCreateSerializer(ModelSerializer):
     memberships = GroupMembershipSerializer(many=True, required=False)

    def create(self, validated_data):
        person_data = validated_data.pop('memberships')
        group = Group.objects.create(**validated_data)
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=group, person=d['person'])
        return group

    def update(self, instance, validated_data):
        person_data = validated_data.pop('memberships')
        for item in validated_data:
            if Group._meta.get_field(item):
                setattr(instance, item, validated_data[item])
        Membership.objects.filter(group=instance).delete()
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=instance, person=d['person'])
        instance.save()
        return instance

    class Meta:
        model = Group

class GroupCreateModelViewSet(ModelViewSet):
    serializer_class = GroupCreateSerializer
    queryset = Group.objects.all()

So you can create a new Group with related Person(s) using:

 { 
     "name" : "Group 1", 
     "memberships" : [ 
         { "person" : 1 },
         { "person" : 2 }
     ]
 }

25👍

Use PrimaryKeyRelatedField shown here:

http://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

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

    class Meta:
        model = Group
        fields = ('name', 'persons')

Create each person first, for example. Person with ID 1, Name = “Bob”. Person with ID 2, Name = “Tim”. Then post them to the REST Endpoint using their primary keys So:

# Group create() REST endpoint data to POST
{'name': 'my group', 'persons': [1, 2]}

Now the people that you had created prior, are part of that Group.

Leave a comment