Unique validator is executed and breaks if field is invalid · Issue #3381 · encode/django-rest-framework (original) (raw)

Suppose there is a simple model:

 class Server(Model):
      ip = GenericIPAddressField(protocol='IPv4', unique=True)

With a basic ModelSeriailzer serializer:

class ServerSerialiser(ModelSerializer):
    class Meta:
        model = Server
        fields = ['ip']

So if I pass an incorrect ip like 123 Django will throw an exception on serializer.is_valid() call.

PostgreSQL complains on a SELECT statement saying that you can't compare inet field with a 123 string.

Here is a traceback:

File "/usr/local/lib/python3.4/site-packages/rest_framework/serializers.py" in is_valid
  197.                 self._validated_data = self.run_validation(self.initial_data)
File "/usr/local/lib/python3.4/site-packages/rest_framework/serializers.py" in run_validation
  541.         value = self.to_internal_value(data)
File "/usr/local/lib/python3.4/site-packages/rest_framework/serializers.py" in to_internal_value
  577.                 validated = self.child.run_validation(item)
File "/usr/local/lib/python3.4/site-packages/rest_framework/serializers.py" in run_validation
  391.         value = self.to_internal_value(data)
File "/usr/local/lib/python3.4/site-packages/rest_framework/serializers.py" in to_internal_value
  421.                 validated_value = field.run_validation(primitive_value)
File "/usr/local/lib/python3.4/site-packages/rest_framework/fields.py" in run_validation
  689.         return super(CharField, self).run_validation(data)
File "/usr/local/lib/python3.4/site-packages/rest_framework/fields.py" in run_validation
  479.         self.run_validators(value)
File "/usr/local/lib/python3.4/site-packages/rest_framework/fields.py" in run_validators
  493.                 validator(value)
File "/usr/local/lib/python3.4/site-packages/rest_framework/validators.py" in __call__
  62.         if queryset.exists():
File "/usr/local/lib/python3.4/site-packages/django/db/models/query.py" in exists
  586.             return self.query.has_results(using=self.db)
File "/usr/local/lib/python3.4/site-packages/django/db/models/sql/query.py" in has_results
  484.         return compiler.has_results()
File "/usr/local/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in has_results
  811.         return bool(self.execute_sql(SINGLE))
File "/usr/local/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in execute_sql
  840.             cursor.execute(sql, params)
File "/usr/local/lib/python3.4/site-packages/debug_toolbar/panels/sql/tracking.py" in execute
  159.         return self._record(self.cursor.execute, sql, params)
File "/usr/local/lib/python3.4/site-packages/debug_toolbar/panels/sql/tracking.py" in _record
  101.             return method(sql, params)
File "/usr/local/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
  79.             return super(CursorDebugWrapper, self).execute(sql, params)
File "/usr/local/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
  64.                 return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.4/site-packages/django/db/utils.py" in __exit__
  97.                 six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python3.4/site-packages/django/utils/six.py" in reraise
  658.             raise value.with_traceback(tb)
File "/usr/local/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
  64.                 return self.cursor.execute(sql, params)

So it dies trying to execute a query. DRF does not stop iterating over validators in run_validators even if one of them failed. I think it should stop as soon as data is bad. Because otherwise next validators can fail badly, like a UniqueValidator.

Looks like Django does the same thing ... This is wrong.