0

假设我有以下模型:

class DataQuery(models.Model):
  name = models.CharField(...)

class Entity(PolymorphicModel):
  class TargetType(models.IntegerChoices):
    Human  = 1,    _('Human')
    Animal = 2,    _('Animal')

  targetType = models.PositiveSmallIntegerField(choices=TargetType.choices, null=False)
  dataQuery = models.OneToOneField(DataQuery, on_delete=models.CASCADE, null=True, related_name="targetEntity")

class HumanEntity(Entity):
  name = models.CharField(...)

  def save(self, *args, **kwargs):
    self.targetType = Entity.TargetType.Human
    return super().save(*args, **kwargs)

class AnimalEntity(Entity):
  numPaws= models.PositiveSmallIntegerField(...)

  def save(self, *args, **kwargs):
    self.targetType = Entity.TargetType.Animal
    return super().save(*args, **kwargs)

使用以下序列化程序:

class HumanSerializer(serializers.ModelSerializer):
    name = serializers.TextField(...)
    class Meta:
        model = HumanEntity
        fields = ('name', )

class AnimalSerializer(serializers.ModelSerializer):
    numPaws = serializers.IntegerField(...)
    class Meta:
        model = AnimalSerializer
        fields = ('numPaws', )

class EntityPolymorphicSerializer(WritableNestedModelSerializer, PolymorphicSerializer):
    model_serializer_mapping = {
        HumanEntity: HumanSerializer,
        AnimalEntity: AnimalSerializer,
    }

    class Meta:
        model = Entity
        fields = '__all__'

class DataQuerySerializer(WritableNestedModelSerializer):
    id = serializers.ReadOnlyField()
    name = serializers.CharField(),
    targetEntity = EntityPolymorphicSerializer()


    class Meta:
        model = DataQuery
        fields = ('id', 'name', 'targetEntity' )

我有一个模型,它与一个或一个模型DataQuery具有 1:1 映射。如果我序列化已经用 a 创建的 a ,我会得到以下(正确的)输出:AnimalEntityHumanEntityDataQueryHumanEntity

{
  id : 1
  name : "testQuery"
  targetEntity : {
   resourcetype : "HumanEntity",
   name : "John Doe"
  }  
}

POST对我的端点的调用也有效,DataQuery并且底层HumanEntity的创建没有任何问题。

我没有故意id在内部Entity序列化程序中包含 an,因为这与此 API 的使用者无关。对他们来说,只需要知道查询可以包含动物或人类。

现在我想更新我的DataQuery实例并将底层更改HumanEntityAnimalEntity. 因此PUT,我如下:

{
  id : 1
  name : "testQuery"
  targetEntity : {
   resourcetype : "AnimalEntity",
   numPaws : 4
  }  
}

而现在,奇怪的事情发生了。没有什么。否AnimalEntity已创建,并且HumanEntity也没有更改(如果我HumanEntity通过输入不同的名称来更改,则名称将正确更改)。似乎可写嵌套DataQuerySerializer并没有完全理解应该关闭底层实例(即删除旧的,创建新的)。

我在这里逐步浏览了相关代码。由于我不想pk在嵌套模型序列化程序中包含 a,因此检索了现有pk的。HumanEntity不知何故(我想这是由于PolymorphicSerializer)这是从正确的序列化程序中完成的,AnimalEntitySerializer. 但是由于传递的字段与底层模型不兼容,所以什么也没有发生。

OneToOneField如果我通过将 1:1 映射到DataQuery类似的位置来反转 1:1 映射:

class DataQuery(models.Model):
  ...
 targetEntity = models.OneToOneField(Entity, on_delete=models.CASCADE, null=True)

它有点工作,但不是真的。每次我进行更新(即使没有更改任何内容),都会创建一个新的HumanEntityor AnimalEntity。但是序列化程序尊重 的变化PUT并创建正确的模型。(不过,旧的并没有被删除)

我期待什么? 执行 a 时PUT,我想更新现有实例,或者,如果我决定切换实体的类型,则创建正确的实例并删除另一个实例。我不确定是否on_delete=CASCADE有任何帮助(无论在哪一边),因为我真正需要的是一个显示If the related field is null, delete myself.

我完全知道我可以(可能很容易)通过覆盖 的update方法来解决这个问题DataQuerySerializer,但是我一开始就不需要了WriteableNestedSerializer

也许我忽略了一些东西,任何帮助将不胜感激。

4

0 回答 0