1

Beta的模型的舞台字段提供了 5 个选项。我希望我的序列化程序不总是接受所有这些选择,而是根据序列化对象的实际阶段值只接受其中一些选择。例如,如果my_beta_object.stage == 1,那么序列化程序应该期望(并提供)只有阶段 2 和 3,如果my_beta_object.stage == 2,只有阶段 2 和 4,等等。

# models.py
class Beta(models.Model):
    class BetaStage(models.IntegerChoices):
        REQUESTED = (1, "has been requested")
        ACCEPTED = (2, "has been accepted")
        REFUSED = (3, "has been refused")
        CORRECTED = (4, "has been corrected")
        COMPLETED = (5, "has been completed")

    stage = models.ChoiceField(choices=self.BetaStage.choices)

# serializers.py
class BetaActionSerializer(serializers.ModelSerializer):
    stage = serializers.ChoiceField(
        # choices=?
    )

    class Meta:
        model = Beta
        fields = ("stage",)

# views.py
class BetaViewSet(viewsets.ModelViewSet):
    serializer_class = BetaSerializer

    def get_serializer_class(self):
        if self.action == "update":
            return BetaActionSerializer
        return self.serializer_class

如何根据序列化对象的字段值动态限制该字段的选择?

4

2 回答 2

1

您可以尝试覆盖__init__序列化程序的方法,然后动态生成选择。然而,它并不像choices=my_generated_choices. 它有点复杂,那里有关于该主题的深入解决方案

另一种更简单的方法是使用该validate()方法,该方法在验证过程结束时触发,每个字段都已成功验证。您可以执行以下操作:

  • 编写一个静态字典,将每个状态映射到其有效的状态选择
  • validateif 方法中updating,使用静态字典检查新状态是否是基于您当前状态的有效选择
  • 如果没有,请提出一个ValidationError
# Example of mapping. Might want to make it pretties and put it in the model itself
mapping = {
  1: [2, 3],
  2: [1, 3],
  # ...
}

# And in validate
def validate(self, data):
    # We're in an update scenario
    if self.instance not None: 
        # It doesnt appear to be required, so use .get()
        new_stage = data.get("stage")
        # Not sure if an instance can have no stage?
        if new_stage is not None and self.instance.stage is not None: 
            # Our check
            if new_stage not in mapping[self.instance.stage]:
                raise ValidationError("Invalid stage")
于 2021-05-15T11:24:09.820 回答
0

部分解释和我在这里找到的解决方案的开始。按照设计,我显然无法在字段初始化时获得上下文。我需要在serializer的初始化时重新定义 ChoiceField 选择属性。

# serializers.py
class BetaActionSerializer(ModelSerializer):
    def __init__(self, *args, **kwargs):
        super(ModelSerializer, self).__init__(*args, **kwargs)
        if self.instance:
            if self.instance.stage == Beta.BetaStage.REQUESTED.value:
                self.fields["stage"].choices = [
                    (Beta.BetaStage.ACCEPTED, Beta.BetaStage.ACCEPTED.name),
                    (Beta.BetaStage.REFUSED, Beta.BetaStage..REFUSED.name),
                ]
            etc.

我没有将此答案标记为解决方案,因为我是原始发帖人,我不确定这是一个可靠或理想的解决方案。但是,我希望这可以帮助将来遇到相同或类似问题的人,因为我自己一直在努力寻找信息。

于 2021-05-18T15:17:54.860 回答