3

Given the following system

#  Models
class Team(models.Model):
    name = models.CharField(max_length=128)


class Player(models.Model):
    name = models.CharField(max_length=128)
    teams = models.ManyToManyField(Team)

#  Serializers
class PlayerSerializer(serializers.ModelSerializer):
    teams = serializers.PrimaryKeyRelatedField(many=True, queryset=League.objects.all(), required=False)

    class Meta:
        model = Team
        fields = ('id', 'name', 'teams')

# Views
class TeamViewSet(viewsets.ModelViewSet):
    queryset = Team.objects.all()
    serializer_class = TeamSerializer

Basically a player can be in many teams

So the question is, how do I implement endpoints to manage the player-team relationship. Say we have two teams with ids 1, and 2 I create a player with

POST /players/ {'name': 'player1'} this player will have Id 1

I want to add player to teams 1 and 2, and then remove player from team 2

With this setup I can do PATCH /players/1/ {'teams': [1, 2]}

How do I now remove player1 from team 2?

Also, is using a patch request to add player1 to teams 1 and 2 the correct way to do this?

Roger Thomas
  • 822
  • 1
  • 7
  • 17
  • possible duplicate of http://stackoverflow.com/questions/39343794/how-to-remove-an-object-from-manytomany-relationship-in-django-rest-framework – Fallen Feb 10 '17 at 12:40

1 Answers1

5

My favorite approach to this problem would be to create a detail route endpoint on your viewset made for this. Here's an example of how that might look:

# Views
class TeamViewSet(viewsets.ModelViewSet):
    queryset = Team.objects.all()
    serializer_class = TeamSerializer

    @action(methods=['delete'], detail=True)
    def remove_players_from_team(self, request):
        team = self.get_object()
        players_to_remove = request.data['players']
        # ...

From there, you could add your logic to remove players from the team. The endpoint would be something along the lines of: <base_url>/api/teams/<team_id>/remove_players_from_team and would expect the argument players and a request type of DELETE, which you can expect any number of ways.

This can be applied to also add players, and could be applied on the reverse relation if desired.

As for which method to allow, think about what's being done. If it's adding players, prefer a POST request. If it's removing them, prefer a DELETE. If you want them to be considered as updating, then use PATCH.

If you're interested in using this, check out the DRF documentation.

aredzko
  • 1,690
  • 14
  • 14
  • 1
    You have given a link to DRF documentation in which `detail_route` is deprecated due to `action` decorator. – Marek Nov 25 '19 at 10:54
  • @Marek Thanks for the edit! I've updated the docs link to reflect your changes. – aredzko Nov 25 '19 at 19:57