#!/usr/bin/env python
# -*- coding: UTF-8 -*-


from django.db import DataError
from rest_framework.exceptions import APIException
from rest_framework.validators import UniqueValidator


class CustomValidationError(APIException):
    """
    继承并重写验证器返回的结果,避免暴露字段
    """

    def __init__(self, detail):
        self.detail = detail


def qs_exists(queryset):
    try:
        return queryset.exists()
    except (TypeError, ValueError, DataError):
        return False


def qs_filter(queryset, **kwargs):
    try:
        return queryset.filter(**kwargs)
    except (TypeError, ValueError, DataError):
        return queryset.none()


class CustomUniqueValidator(UniqueValidator):
    """
    继承,重写必填字段的验证器结果,防止字段暴露
    """

    def filter_queryset(self, value, queryset, field_name):
        """
        Filter the queryset to all instances matching the given attribute.
        """
        filter_kwargs = {f"{field_name}__{self.lookup}": value}
        return qs_filter(queryset, **filter_kwargs)

    def exclude_current_instance(self, queryset, instance):
        """
        If an instance is being updated, then do not include
        that instance itself as a uniqueness conflict.
        """
        if instance is not None:
            return queryset.exclude(pk=instance.pk)
        return queryset

    def __call__(self, value, serializer_field):
        # Determine the underlying model field name. This may not be the
        # same as the serializer field name if `source=<>` is set.
        field_name = serializer_field.source_attrs[-1]
        # Determine the existing instance, if this is an update operation.
        instance = getattr(serializer_field.parent, "instance", None)

        queryset = self.queryset
        queryset = self.filter_queryset(value, queryset, field_name)
        queryset = self.exclude_current_instance(queryset, instance)
        if qs_exists(queryset):
            raise CustomValidationError(f"{self.message}（{value}）")

    def __repr__(self):
        return super().__repr__()
