为了账号安全,请及时绑定邮箱和手机立即绑定

DRF 使用嵌套序列化程序和外键创建对象

DRF 使用嵌套序列化程序和外键创建对象

慕田峪7331174 2022-12-20 09:49:47
我正在使用 DRF,我正在尝试创建一个具有多个外键的对象以及需要在此过程中创建的相关对象。这是我的模型的简化版本:class Race(models.Model):    name = models.CharField(max_length=200)    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='races')    type = models.ForeignKey(Type, on_delete=models.SET_NULL, related_name='races', null=True)    region = models.ForeignKey(Region, on_delete=models.CASCADE, verbose_name=_('region'), related_name='races')    country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name='races')    timezone = models.ForeignKey(Timezone, on_delete=models.SET_NULL, null=True)class Event(models.Model):    name = models.CharField(max_length=200)    race = models.ForeignKey(Race, on_delete=models.CASCADE, related_name='events')然后这是我的 Race 序列化程序:class RaceSerializer(serializers.ModelSerializer):    owner = UserSerializer(read_only=True)    type = TypeSerializer(read_only=True)    events = EventSerializer(many=True)    country = CountrySerializer()    region = RegionSerializer(read_only=True)    timezone = TimezoneSerializer(read_only=True)    def create(self, validated_data):        with transaction.atomic():            events = validated_data.pop('events', None)            race = Race(**validated_data)            race.save()            for event in events:                Event.objects.create(race=race, **event)        return race我的看法:class AddRaceView(CreateAPIView):    serializer_class = RaceSerializer    permission_classes = (IsAuthenticated,)    def perform_create(self, serializer):        serializer.save(owner=self.request.user)所以我遇到的问题是将有效数据传递给外键的序列化程序。我不想为Type、Region、Country、创建新对象Timezone,只传递适当的数据,以便新创建的 Race 对象正确引用现有的外键。这是我尝试过的:1) 没有read_only=True在外键序列化器上设置。这会尝试创建我不想要的新对象。2)设置read_only=True外键序列化器(如上面的代码)。这有助于不尝试创建新Type的等对象,而是从序列化程序创建方法中Region删除相应的字段。validated_data所以我无法在创建时将现有对象添加到 Race 外键。3) 使用 PrimaryKeyForeignField 而不是TypeSerializer等RegionSerializer。但是当我RaceSerializer用来检索比赛数据时,我只有一个pkundertype等region,我真的很想能够检索外键的所有字段。您能否建议正确的设置会寻找这样的东西?我觉得它不应该这么难。
查看完整描述

1 回答

?
MMMHUHU

TA贡献1834条经验 获得超8个赞

所以最后我通过RelatedField为每个外键使用而不是单独的序列化器解决了这个问题,除了嵌套EventSerializer的是真正需要编写嵌套Event对象的。


这是RaceSerializer:


class RaceSerializer(serializers.ModelSerializer):

    owner = UserSerializer(read_only=True)

    type = TypeField()

    country = CountryField()

    region = RegionField()

    timezone = TimezoneField()

    events = EventSerializer(many=True)

    race_cal_types = serializers.SerializerMethodField()


    def create(self, validated_data):

        with transaction.atomic():

            events = validated_data.pop('events', None)

            race = Race(**validated_data)

            race.save()

            for event in events:

                Event.objects.create(race=race, **event)

        return race

这是我在我的每个字段中使用的组合RelatedField,例如外键:ModelSerializerRaceSerializerregion


class RegionSerializer(serializers.ModelSerializer):


    class Meta:

        model = Region

        fields = ('pk', 'name', 'code')



class RegionField(RelatedField):


    def get_queryset(self):

        return Region.objects.all()


    def to_internal_value(self, data):

        return self.get_queryset().get(**data)


    def to_representation(self, value):

        return RegionSerializer(value).data

每个字段 ( type, region, country, timezone) 都有自己的to_internal_value方法to_representation,可以按照我需要的方式序列化/反序列化数据。


查看完整回答
反对 回复 2022-12-20
  • 1 回答
  • 0 关注
  • 161 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号