Repository: encode/django-rest-framework

Issue:
error_messages on serializer fields should also be used by validators.
```
email = models.EmailField(
    unique=True,
    error_messages={
        'unique': 'my message'
    }
)
```

This does not show the defined error as expected when the field is not unique. The message is still the default: "This field must be unique.".



Discussion:
I see. We automatically add `UniqueValidator` for model fields that have `unique=True` [here](https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/utils/field_mapping.py#L186). 

@tomchristie I wonder if we should be forwarding `error_messages['unique']` to `UniqueValidator`, which IMHO seems like we should.

@hobarrera A workaround  might be to subclass `UniqueValidator` and change the message there. Then in your serializer manually add your email field with that validator.

> @tomchristie I wonder if we should be forwarding error_messages['unique'] to UniqueValidator, which IMHO seems like we should.

I believe that that makes sense and is what would usually be expected by most developers.

> @hobarrera A workaround might be to subclass UniqueValidator and change the message there. Then in your serializer manually add your email field with that validator.

Yes, that's what I did. In case anybody else needs a bit more details on this workaround:

```
class ClientSerializer(serializers.ModelSerializer):

    email = serializers.EmailField(validators=[
        UniqueValidator(
            queryset=Client.objects.all(),
            message="This email is already in use.",
        )]
    )
    # ...
```

Is the proposed enhancement to take the error messages from what's defined on the model level and forward them on?
Edit: I'd be interested in working on this, if so.

> Is the proposed enhancement to take the error messages from what's defined on the model level and forward them on?

Yes, that's what's expected (and it's done for other validators, unless I'm mistaken).

Seems reasonable to me for us to check the validator codes and apply the field error message if one exists, yup. No objection to this from me.

+1 any progress on this one? is this saying we can define error message on the Model level as in https://docs.djangoproject.com/en/1.8/ref/models/fields/#error-messages?

> +1 any progress on this one?

No, if there's progress you'd see it here.

> is this saying we can define error message on the Model level

Yup

cool, if you tell me the general idea for how that should work or where I need to make updates I can take a stab at it...

You'd need to change something here, at least:
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/utils/field_mapping.py#L195

That's where a UniqueValidator is automatically added to the serializer for fields with unique constraints.
It takes an optional message parameter.

I'm not quite sure how to get the message off of the model field, though.

> I'm not quite sure how to get the message off of the model field, though.

Error messages for a specific field [are available as `field.error_messages`](https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.Field.error_messages). The unique message uses the key `unique`.


Resolving patch:
diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py
--- a/rest_framework/utils/field_mapping.py
+++ b/rest_framework/utils/field_mapping.py
@@ -193,7 +193,15 @@ def get_field_kwargs(field_name, model_field):
         ]
 
     if getattr(model_field, 'unique', False):
-        validator = UniqueValidator(queryset=model_field.model._default_manager)
+        unique_error_message = model_field.error_messages.get('unique', None)
+        if unique_error_message:
+            unique_error_message = unique_error_message % {
+                'model_name': model_field.model._meta.object_name,
+                'field_label': model_field.verbose_name
+            }
+        validator = UniqueValidator(
+            queryset=model_field.model._default_manager,
+            message=unique_error_message)
         validator_kwarg.append(validator)
 
     if validator_kwarg:


Test patch:
diff --git a/tests/test_validators.py b/tests/test_validators.py
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -48,7 +48,7 @@ def test_is_not_unique(self):
         data = {'username': 'existing'}
         serializer = UniquenessSerializer(data=data)
         assert not serializer.is_valid()
-        assert serializer.errors == {'username': ['This field must be unique.']}
+        assert serializer.errors == {'username': ['UniquenessModel with this username already exists.']}
 
     def test_is_unique(self):
         data = {'username': 'other'}