Могу ли я заставить сериализатор выйти из строя молча? - PullRequest
0 голосов
/ 28 декабря 2018

Я должен сериализовать список адресов электронной почты.Если один из них содержит неправильный символ (в одном случае это был символ «:» в конце адреса), мой сериализатор выдает ошибку, отклоняет сериализацию всего набора адресов и возвращает HTTP 400. Есть ли способ«вытолкнуть» ошибочный адрес электронной почты из списка, но все еще сериализовать оставшиеся правильные адреса?

Просмотр:

@action(detail=False, methods=['post'])
def match(self, request):
    serializer = FriendFinderSerializer(data=request.data, many=True)
    if serializer.is_valid():
        contacts = serializer.validated_data
        matched, unmatched = self.match_contacts(contacts)
        serialized_matched = FriendFinderSerializer(matched, many=True)
        serialized_unmatched = FriendFinderSerializer(unmatched, many=True)
        data = {
            'matched': serialized_matched.data,
            'unmatched': serialized_unmatched.data,
        }
        return Response(data, status=status.HTTP_200_OK)
    else:
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Сериализатор:

class FriendFinderSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    image = serializers.ImageField(required=False)
    record_id = serializers.CharField()
    phone_numbers = serializers.ListField(child=serializers.CharField(), required=False)
    email_addresses = serializers.ListField(child=serializers.EmailField(), required=False)
    relationship_id = serializers.CharField(required=False)
    relationship_status = serializers.CharField(required=False)

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Это своего рода хак, но это работает.

Вам нужно определить пользовательское поле и там вам нужно переопределить to_internal_value метод поля.Например:

class CustomField(serializers.Field):

    def __init__(self, custom_validation, *args, **kwargs):
        self.custom_validation=custom_validation  # <-- Here pass your custom validation regex
        super(CustomField, self).__init__(*args, **kwargs)

    def to_representation(self, obj):
            return obj

    def to_internal_value(self, obj):
        try:
            match = re.search(self.custom_validation, obj)  # <-- validate the value against regex
            if match:
                return obj
        except Exception as e:
            pass
        return None  # <-- If exception occurs, return None

Или переопределить EmailField следующим образом:

class CustomEmailField(serializer.EmailField):
     def run_validation(self,*args, **kwargs):
        try:
            return super(CustomEmailField, self).run_validation(*args,**kwargs)  # <-- Runs validation, but it fails, returns None
        except:
            return None

И использовать его в Сериализаторе следующим образом:

email = CustomField(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)")  # regex for email

Или

email = CustomEmailField()

И если вы хотите получить недопустимые значения из ListField, вы можете переопределить to_representation следующим образом:

class CustomListField(serializers.ListField):
    def to_representation(self, data):
        childs = super(CustomListField, self).to_representation(data)
        new_childs = []
        for child in childs:
            if child:
                new_childs.append(child)
        return new_childs

Затем используйте его в Сериализаторе:

email_addresses = CustomListField(child=CustomEmailField(), required=False)
0 голосов
/ 28 декабря 2018

Для начала нужно перебрать request.data и обработать каждый элемент в цикле.Это определенно является нарушением нормы, и вам необходимо определить, как обращаться со случаями, когда есть хорошие и плохие данные.

@action(detail=False, methods=['post'])
def match(self, request):
    successful_data = []
    error_data = []
    for element in request.data:
        serializer = FriendFinderSerializer(data=element, many=False)
        if serializer.is_valid():
            contacts = serializer.validated_data
            matched, unmatched = self.match_contacts(contacts)
            serialized_matched = FriendFinderSerializer(matched, many=True)
            serialized_unmatched = FriendFinderSerializer(unmatched, many=True)
            successful_data.append({
                'matched': serialized_matched.data,
                'unmatched': serialized_unmatched.data,
            })
        else:
            error_data.append(serializer.errors)
    # Determine what status to return and how to handle successes and errors.

Лично я бы либо делал меньшие запросы, чем публиковал бы вседанные или обработать случай, когда ошибка в одном FriendFinderSerializer приводит к сбою всех.То, что вы пытаетесь сделать, может причинить вам больше боли, чем другие варианты.

...