'Django Serialization - Partial update on nested objects
Searched around for a few hours on this and I am surprised I couldn't find an answer but here it goes.
Let's say I have the following models:
class Mission(models.Model):
mission_name = models.CharField(max_length=150)
...
class Player(models.Model):
player_name = models.CharField(max_length=150, unique = True)
state = models.CharField(max_length=150)
currentMission = models.ForeignKey(Mission,on_delete=models.SET_NULL, blank=True, null=True))
Objectives:
- When creating a mission, I would like to provide the players' names that are going to participate on this mission (Names are unique). That means, when mission is created, I have to update the
currentMissionfield of each given player. (Players already exist when mission is created) - When I try to
GETa mission, I would like to see the names of the players that participate
My attempt
Class MissionSerializer(serializers.ModelSerializer):
#This is to get a list of the players that participate in this mission
players = PlayerSerializer(many=True, read_only=True)
class Meta:
model= Mission
fields = ['mission_name','players']
def create(self,validated_data):
mission = Mission.objects.create(**validated_data)
# Notice that I get the "players" data from "self.initial_data" and not from validated_data
# This is because validated_data does not have the "players" field,
# (I guess because I didn't provide all the required fields on my request for the player. I just provided the players' names )
players_data = self.initial_data['players']
#Update each player's current mission
for player_data in players_data:
qs = Player.objects.filter(player_name=player_data['player_name'])
obj = get_object_or_404(qs)
serializer = PlayerSerializer(obj, data={'currentMission': mission.id}, partial=True)
if (serializer.is_valid()):
serializer.save()
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('__all__')
def update(self, instance, validated_data):
instance.currentMission = validated_data['currentMission']
instance.save()
return instance
The above works for objective #1. However, it does not work for objective #2. That is, when I GET a mission, the list of players is not present on the result.
My question is, how could I also retrieve this list when performing GET requests?
Solution 1:[1]
I think that players field lacks a source. Adding a source to the field should solve your problem.
players = PlayerSerializer(many=True, read_only=True, source='player_set')
Also, I'd recommend to prefetch that players to optimize the database query.
In your view;
mission_queryset = Mission.objects.filter(...).prefetch_related('player_set')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cagatay Barin |
