【问题标题】:Django - DRF ValidationsDjango - DRF 验证
【发布时间】:2018-07-03 10:42:54
【问题描述】:

我正在设计一个可供不同合作伙伴使用的 API。以下是 API 虚拟负载:-

{
    key1: value1,
    key2: value2,
    key3: value3,
    key4: value4,
    key5: value5,
    partner: partner_code
}

现在,我有一个模型需要保存上述字段。

class Table(models.Model):
    key1 = models.IntegerField()    
    key2 = models.IntegerField(blank=True, null=True)    
    key3 = models.IntegerField()
    key4 = models.IntegerField(blank=True, null=True)    
    key5 = models.CharField(max_length=255)
    partner = models.ForeignKey(Partner)

另外,我有一个序列化器:-

class TableSerializer(models.Model):
    class Meta:
        model = Table
        fields = '__all__'

现在,每当发布数据时,我都会序列化(并验证)数据,然后保存它。这是我的做法。

serializer = TableSerializer(data=payload)
if serializer.is_valid():
    serializer.save()

这是正常的 DRF 流程。现在,出现的问题是我需要对每个合作伙伴应用自定义验证。例如:-

`key2` and `key4` are mandatory for PartnerA. Similarly, for PartnerB, max value of `key1` is 100 and many more.

根据当前的 DRF 流程,我需要在序列化程序中添加 if-else 条件。

class TableSerializer(models.Model):
    def validate(self, data):
        if partner == `partnerA`:
            # checkfor key1 max value.
            # check the mandatory fields.
        elif partner == `partnerB`:
            # some custom validations
        # and so on
    class Meta:
        model = Table
        fields = '__all__'

这个if-else 可以继续增长,这是一个糟糕的设计。如何引入另一个名为 Validation Engine 的组件,它可以首先验证数据,然后将验证后的数据传递给 DRF 序列化程序?

【问题讨论】:

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


    【解决方案1】:

    您可以使用合作伙伴 == partnerB 或类似的方式编写更多序列化程序(此序列化程序仅用于验证),然后执行此操作:

    def validate(self, data):
        data_is_valid = False
        for serializer_class in selializers_for_validate:
            serializer = serializer_class(data=data)
            is_valid = serializer.is_valid()
            if is_valid:
                break
        if not is_valid:
            raise serializers.ValidationError(<here your custom error>)
        return data
    

    我觉得这个决定不太好,但是你可以试试, 或者您可以编写自定义验证器并在验证中使用它

    【讨论】:

      【解决方案2】:

      我建议制作基本序列化程序,只进行基本验证和合作伙伴 id/name/type/etc 到特定序列化程序之间的映射:

      from django.db import models
      from rest_framework import serializers
      from rest_framework.viewsets import ModelViewSet
      
      
      # models.py
      class Table(models.Model):
          key1 = models.IntegerField()
          key2 = models.IntegerField(blank=True, null=True)
          key3 = models.IntegerField()
          key4 = models.IntegerField(blank=True, null=True)
          key5 = models.CharField(max_length=255)
          partner = models.ForeignKey(Partner)
      
      
      # serializers.py
      class TableSerializer(serializers.ModelSerializer):
          partner_serializers = {}
      
          class Meta:
              model = Table
              fields = '__all__'
      
          def validate(self, data):
              self.partner_serializers[data['partner']['partner_id']](
                  instance=self.instance,
                  data=data
              ).is_valid(raise_exception=True)
      
              return super().validate(data)
      
          @classmethod
          def register_partner_validator(cls, partner_id):
              def wrapped(serializer):
                  cls.partner_serializers[partner_id] = serializer
                  return serializer
      
              return wrapped
      
      
      @TableSerializer.register_partner_validator('thePartner1')
      class Partner1TableSerializer(TableSerializer):
          class Meta:
              extra_kwargs = {
                  'key3': {'max_value': 3}
              }
      
          def validate(self, data):
              if data['key1'] + data['key2'] > 5:
                  raise serializers.ValidationError('Wrong!')
      
      
      @TableSerializer.register_partner_validator('thePartner2')
      class Partner2TableSerializer(TableSerializer):
          def validate(self, data):
              if data['key1'] + data['key5'] < 5:
                  raise serializers.ValidationError('Wrong!')
      
      
      # views.py
      class TableViewSet(ModelViewSet):
          queryset = Table.objects.all()
          serializer_class = TableSerializer
      
      

      【讨论】:

        猜你喜欢
        • 2015-12-30
        • 1970-01-01
        • 2020-08-14
        • 2019-03-03
        • 2017-06-05
        • 2017-10-29
        • 1970-01-01
        • 2020-05-23
        • 2020-07-15
        相关资源
        最近更新 更多