在使用 Django Rest Framework 时,尝试编写一个创建方法来写入嵌套字段,但发现嵌套对象没有被写入。以下是示例代码:
class MessagesSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.IntegerField(source='pk', read_only=True)
suggested_songs = SongSerializer()
class Meta:
model = Messages
fields = ('id','owner','url','suggested_songs',)
#fields = ('id','url','suggested_songs',)
def create(self, validated_data):
song_data = validated_data.pop('suggested_songs')
message = Messages.objects.create(**validated_data)
Song.objects.create(**song_data)
return message
class SongSerializer(serializers.HyperlinkedModelSerializer):
#id = serializers.IntegerField(source='pk', read_only=True)
class Meta:
model = Song
fields = ('id','title','artist','album','albumId','num_votes','cleared')
read_only_fields = ('song_id')
class Messages(models.Model):
owner = models.OneToOneField(User, primary_key=True, related_name='user_messages', editable=False) #TODO, change owner to 'To'
#suggested_songs = models.ManyToManyField(Song, related_name='suggested_songs')
suggested_songs = models.ForeignKey(Song, null=True, blank=True)
# If a user is added, this runs.
@receiver(post_save, sender=User)
def create_friend_for_user(sender, instance=None, created=False, **kwargs):
if created:
Messages.objects.get_or_create(owner=instance)
# Same as above, but for deletion
@receiver(pre_delete, sender=User)
def delete_friend_for_user(sender, instance=None, **kwargs):
if instance:
Messages.objects.get(owner=instance).delete()
class Song(models.Model):
"""
A model which holds information about the songs.
"""
#song_id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=150, blank=True, default='')
artist = models.CharField(max_length=150, blank=True, default='')
album = models.CharField(max_length=150, blank=True, default='')
albumId = models.CharField(max_length=150, blank=True, default='')
num_votes = models.IntegerField(default=0, blank=True)
cleared = models.BooleanField(default=False, blank=True)
class Meta:
ordering = ('title',)
#managed=True
解决方案
在 MessagesSerializer.create 方法中,需要先创建 Song 对象,然后将 Song 的外键传递给 Messages.create 方法。以下是修改后的代码:
class MessagesSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.IntegerField(source='pk', read_only=True)
suggested_songs = SongSerializer()
class Meta:
model = Messages
fields = ('id','owner','url','suggested_songs',)
#fields = ('id','url','suggested_songs',)
def create(self, validated_data):
song_data = validated_data.pop('suggested_songs')
song = Song.objects.create(**song_data)
# song need to be created first because the foreign key is in
# the Messages model
message = Messages.objects.create(suggested_songs=song, **validated_data)
return message
class SongSerializer(serializers.HyperlinkedModelSerializer):
#id = serializers.IntegerField(source='pk', read_only=True)
class Meta:
model = Song
fields = ('id','title','artist','album','albumId','num_votes','cleared')
read_only_fields = ('song_id')
class Messages(models.Model):
owner = models.OneToOneField(User, primary_key=True, related_name='user_messages', editable=False) #TODO, change owner to 'To'
#suggested_songs = models.ManyToManyField(Song, related_name='suggested_songs')
suggested_songs = models.ForeignKey(Song, null=True, blank=True)
# If a user is added, this runs.
@receiver(post_save, sender=User)
def create_friend_for_user(sender, instance=None, created=False, **kwargs):
if created:
Messages.objects.get_or_create(owner=instance)
# Same as above, but for deletion
@receiver(pre_delete, sender=User)
def delete_friend_for_user(sender, instance=None, **kwargs):
if instance:
Messages.objects.get(owner=instance).delete()
class Song(models.Model):
"""
A model which holds information about the songs.
"""
#song_id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=150, blank=True, default='')
artist = models.CharField(max_length=150, blank=True, default='')
album = models.CharField(max_length=150, blank=True, default='')
albumId = models.CharField(max_length=150, blank=True, default='')
num_votes = models.IntegerField(default=0, blank=True)
cleared = models.BooleanField(default=False, blank=True)
class Meta:
ordering = ('title',)
#managed=True