Pan*_*nos 4 python django django-rest-framework
我正在使用 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')
Run Code Online (Sandbox Code Playgroud)
这是我的 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
Run Code Online (Sandbox Code Playgroud)
以及我的看法:
class AddRaceView(CreateAPIView):
serializer_class = RaceSerializer
permission_classes = (IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
Run Code Online (Sandbox Code Playgroud)
这是我通过 POST 请求发送的一些测试数据:
{
"name": "ABC Marathon",
"country": {
"pk": 1,
"name": "United States"
},
"region": {
"pk": 1,
"code": "ME"
},
"timezone": {
"pk": 1,
"code": "EST"
},
"events": [
{
"name": "Marathon"
},
{
"name": "Half Marathon"
}
]
}
Run Code Online (Sandbox Code Playgroud)
所以我遇到的问题是将有效数据传递给外键的序列化器。我不想为Type
、Region
、Country
、创建新对象Timezone
,只传递适当的数据,以便新创建的 Race 对象正确引用现有外键。
这是我尝试过的:
1) 未设置read_only=True
外键序列化器。这试图创建我不想要的新对象。
2)read_only=True
外键序列化器的设置(如上面的代码)。这有助于不尝试创建新的Type
等对象,而是从序列化器创建方法中Region
删除相应的字段。validated_data
所以我无法在创建时将现有对象添加到 Race 外键中。
3)使用 PrimaryKeyForeignField 而不是等TypeSerializer
。RegionSerializer
但是当我用来RaceSerializer
检索竞赛数据时,我只有一个pk
undertype
等region
,我真的希望能够检索外键的所有字段。
您能否建议一下对于这样的事情,正确的设置会是什么样子?我觉得这不应该这么难。
谢谢你!
所以最后我通过对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
Run Code Online (Sandbox Code Playgroud)
这是我在 my 中的每个字段使用的RelatedField
和的组合,例如外键:ModelSerializer
RaceSerializer
region
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
Run Code Online (Sandbox Code Playgroud)
每个字段(type
、、、、)都有自己的方法,region
可以按照我需要的方式序列化/反序列化数据。country
timezone
to_internal_value
to_representation
归档时间: |
|
查看次数: |
3754 次 |
最近记录: |