Сериализация Django - частичное обновление вложенных объектов
Поискал несколько часов на эту тему и удивлен, что не нашел ответа, но вот он.
Допустим, у меня есть следующие модели:
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))
Цели:
- 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
Моя попытка
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
Вышеизложенное работает для цели №1. Однако это не работает для цели #2. То есть, когда я GET выполняю миссию, список игроков не присутствует в результате.
Мой вопрос в том, как я могу также получить этот список при выполнении GET запросов?
Я думаю, что в поле players отсутствует источник. Добавление источника к полю должно решить вашу проблему.
players = PlayerSerializer(many=True, read_only=True, source='player_set')
Кроме того, я бы рекомендовал предварительную выборку игроков для оптимизации запроса к базе данных.
По вашему мнению;
mission_queryset = Mission.objects.filter(...).prefetch_related('player_set')