如何将 UniqueTogetherValidator 显示为字段错误而不是非字段错误?

Umu*_*kun 5 python django django-models django-views django-rest-framework

我有一个像这样的序列化器:

class ContactSerializer(serializers.ModelSerializer):
    class Meta:
        model = Contact
        fields = (
            'account', 'first_name', 'last_name', 'email',
            'phone_number',
        )
        validators = [
            UniqueTogetherValidator(
                queryset=Contact.objects.all(),
                fields=['account', 'phone_number'],
                message='A contact with this phone number is already exists.',
            ),
        ]
Run Code Online (Sandbox Code Playgroud)

API 将唯一的一起验证器错误返回为non_field_errors。我想在特定领域展示它。在这种情况下phone_number

我怎样才能做到这一点?

小智 1

我制作了自己的验证器:

class UniqueForeignValidator(UniqueValidator):
    message = 'The {field} must be unique within {foreign}'
    requires_context = True

    def __init__(self, queryset, foreign_field, message=None, lookup='exact'):
        super().__init__(queryset, message, lookup)
        self.foreign_field = foreign_field

    def __call__(self, value, serializer_field):
        foreign_pk = serializer_field.parent.initial_data[self.foreign_field]
        self.message = self.message.format(field=serializer_field.field_name, foreign=self.foreign_field)
        filter_kwargs = {f'{self.foreign_field}': foreign_pk}
        self.queryset = self.queryset.filter(**filter_kwargs)
        return super().__call__(value, serializer_field)
Run Code Online (Sandbox Code Playgroud)

对于您的示例,应该这样调用:

class ContactSerializer(serializers.ModelSerializer):
    phone_number = fields.CharField(
        validators=[
            UniqueForeignValidator(
                queryset=Contact.objects.all(),
                foreign_field='account'
            )
        ]
    )
    
    class Meta:
        model = Contact
        fields = (
            'account', 'first_name', 'last_name', 'email',
            'phone_number',
        )
Run Code Online (Sandbox Code Playgroud)

您可以在序列化器中调用验证器时覆盖该消息

UniqueForeignValidator(
    queryset=Contact.objects.all(),
    foreign_field='account',
    message='A contact with this phone number is already exists.'
)
Run Code Online (Sandbox Code Playgroud)