Джанго - DRF Validations - PullRequest
0 голосов
/ 03 июля 2018

Я разрабатываю 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?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Я предлагаю сделать базовый сериализатор только с базовой проверкой и сопоставить идентификатор партнера / имя / тип / и т. Д. С конкретным сериализатором:

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

0 голосов
/ 03 июля 2018

Вы можете написать еще несколько сериализаторов (эти сериализаторы будут только для проверки) с партнером == 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

Я думаю, что это решение не очень хорошее, но вы можете попробовать, или вы можете написать свои собственные валидаторы и использовать их в validate

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...