【问题标题】:Django Rest Framework - conditionally make serializer's field required or not using other field valueDjango Rest Framework - 有条件地使序列化程序的字段成为必需或不使用其他字段值
【发布时间】:2019-10-07 21:50:32
【问题描述】:

在我的 DRF 项目中,我有一个模型:

class Item(BaseModel):
    PRIVATE = 'PRIVATE'
    COMPANY = 'COMPANY'
    ACCOUNT_TYPES = (
        (PRIVATE, _('Private')),
        (COMPANY, _('Company')),
    )
    company_name = models.CharField(max_length=128, null=True, blank=True)
    person_name = models.CharField(max_length=128, null=True, blank=True)
    account_type = models.CharField(max_length=32, choices=ACCOUNT_TYPES)
    phone = models.CharField(max_length=128, null=True, blank=True)
    email = models.EmailField(max_length=128, null=True, blank=True)

和序列化器中的 ItemSerializer,如:

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('account_type', 'company_name', 'person_name')

    def create(self, validated_data):
        print('ItemSerializer, create')
        print('validated_data:', validated_data)
        return super().create(validated_data)

    def validate(self, attrs):
        print('ItemSerializer validate, attrs:', attrs)
        return attrs

在模型中可以看到,有company_nameperson_name这两个字段,模型中都不需要。

要创建项目,必须指定account_type。它可以是PRIVATECOMPANY

现在,如果帐户类型是公司或私人,我想在我的序列化程序中指定特定字段。例如,account_type 是 COMPANY,我想将字段 company_name 设为必填。如果 account_type 是 PRIVATE 我想让person_name 是必需的。

  1. 哪种方法适合实现这一目标,我该如何做到这一点?
  2. 同样使用上述逻辑,我想在现场做额外的验证。示例:是account_typePRIVATE 并且person_name 不为空,我想对person_name 进行一些验证(检查它是否具有正确的格式、长度等)

【问题讨论】:

    标签: python django django-models django-rest-framework


    【解决方案1】:

    您可以使用接收所有序列化字段作为参数的序列化程序的validate方法,请参阅here

    【讨论】:

    • 没有说明如何将特定字段标记为必填项。
    • 在那个级别,由你来添加逻辑。如果不满足要求,请提高 serializers.ValidationError
    • 我认为不可能有条件地将字段标记为必填项,在validate 方法中,您可以检查该字段是否存在,如果不存在,您可以提出ValidationError与适当的消息。另一种解决方案是使用 2 个不同的序列化程序,一个用于 PRIVATE,另一个用于 COMPANY
    • @piedra 如果我在 validate 方法中引发 ValidationError,错误将被列为“non_field_errors” - 我希望将错误消息绑定到字段。
    【解决方案2】:

    您可以定义两个序列化程序 PrivateSerializerCompanySerializer,然后在您看来,使用方法 .get_serializer_class() 并根据请求中发送的内容返回一个或另一个。

    这样您就可以根据情况定义每个序列化程序验证。

    【讨论】:

      【解决方案3】:

      您可以使用def validate(self, data) 来检查需要的条件, 和def validate_{field_name}(self, value) 进行额外验证:

      class ItemSerializer(serializers.ModelSerializer):
          class Meta:
              model = Item
              fields = ('account_type', 'company_name', 'person_name')
              extra_kwargs = {
                  'company_name': {'required': False},
                  'person_name': {'required': False},
              }
      
          def validate(self, data):
              data_dict = dict(data)
              data_keys = data.keys()
              account_type= data_dict.get('account_type')
              if account_type == 'PRIVATE' and 'person_name' not in data_keys:
                  raise serializers.ValidationError('person_name required when account_type is PRIVATE.')
              if account_type == 'COMPANY' and 'company_name' not in data_keys:
                  raise serializers.ValidationError('company_name required when account_type is COMPANY.')
              return data
      
          def validate_person_name(self, value):
              if len(value) < 10:
                  raise serializers.ValidationError('person_name must be at least 10 characters.')
              return value
      

      【讨论】:

        猜你喜欢
        • 2013-11-15
        • 2015-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多