我可以使序列化程序静默失败吗?

时间:2018-12-28 14:56:43

标签: django python-3.x django-rest-framework

我必须序列化电子邮件地址列表。如果其中一个包含错误的字符(在一种情况下,其末尾是一个“:”),我的序列化器将引发错误,拒绝序列化整个地址集并返回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 :(得分:1)

一个开始的地方是遍历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中的错误导致全部失败的情况。您尝试执行的操作可能会比其他选择引起更多的痛苦。

答案 1 :(得分:0)

这是一种骇客,但可以。

您需要定义一个自定义字段,并且那里需要覆盖该字段的/messages方法。像这样:

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