title: In Django REST Framework, why do serializers properly handle field-level validation exceptions in models but not object-level validation?
body: <p>To illustrate my problem, let's say I have a simple <code>Person</code> model defined like this:</p>
  <pre><code>from django.db import models
  from django.core.validators import MinLengthValidator, MaxLengthValidator, ValidationError
  
  class Person(models.Model):
      first_name = models.CharField(max_length=100, null=False, blank=False,
                                    validators=[MinLengthValidator(limit_value=1),
                                                MaxLengthValidator(limit_value=100)])
      last_name = models.CharField(max_length=100, null=True, blank=True,
                                   validators=[MinLengthValidator(limit_value=1),
                                               MaxLengthValidator(limit_value=100)])
  
      def clean(self):
          self.validate()
          super().clean()
  
      def save(self, *args, **kwargs):
          self.full_clean()
          super().save(*args, **kwargs)
  
      def validate(self):
          &quot;&quot;&quot;The first and last names cannot be the same strings.&quot;&quot;&quot;
          if (self.first_name and self.last_name and
                  self.first_name.lower() == self.last_name.lower()):
              raise ValidationError('First and last names, if both are provided, cannot be the same.',
                                    code='invalid',
                                    params={'first_name': self.first_name,
                                            'last_name': self.last_name})
  </code></pre>
  <ul>
  <li>Notice that both the <code>first_name</code> and <code>last_name</code> fields have <em>field-level</em> validation associated with them. (My dev database is SQLite, and it does not do length validation. So I had to add <code>validators</code>. But that is not my question.)</li>
  </ul>
  <p>I defined two simple <code>APIView</code>-based classes:</p>
  <pre><code>from rest_framework import generics
  from ..models import Person
  from ..serializers import PersonSerializer
  
  class PersonDetailView(generics.RetrieveUpdateDestroyAPIView):
      name = 'person-detail'
      queryset = Person.objects.all()
      serializer_class = PersonSerializer
      lookup_field = 'id'
  
  class PersonListView(generics.ListCreateAPIView):
      name = 'person-list'
      queryset = Person.objects.all()
      serializer_class = PersonSerializer
      lookup_field = 'id'
  </code></pre>
  <p>I defined a serializer based on Django REST Framework's <code>ModelSerializer</code>:</p>
  <pre><code>from rest_framework import serializers
  from ..models import Person
  
  class PersonSerializer(serializers.ModelSerializer):
      class Meta:
          model = Person
          fields = ('id', 'first_name', 'last_name')
  </code></pre>
  <p>And, I mapped some URLs.</p>
  <p>If I POST, PUT, or PATCH such that I violate the <strong>field-level</strong> validation rules (e.g., I try to submit a first name that is 101 character long), Django REST Framework catches the exception from the model class and displays it appropriately. Here's what it looks like in the browsable API:</p>
  <p><a href="https://i.stack.imgur.com/zBbYy.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zBbYy.jpg" alt="enter image description here" /></a></p>
  <p>But, if I POST, PUT, or PATCH such that I violate the <strong>object-level</strong> validation rule, Django REST framework does not catch the exception, and the server crashes and displays a trace like this:</p>
  <p><a href="https://i.stack.imgur.com/kSSuK.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/kSSuK.jpg" alt="enter image description here" /></a></p>
  <p>My solution has been to add object-level validation to the serializer as well as to the model. Here's the serializer with its own <code>validate</code> method:</p>
  <pre><code>from rest_framework import serializers
  from rest_framework.validators import ValidationError
  
  from ..models import Person
  
  class PersonSerializer(serializers.ModelSerializer):
      class Meta:
          model = Person
          fields = ('id', 'first_name', 'last_name')
  
      def validate(self, attrs):
          first_name = attrs.get('first_name')
          last_name = attrs.get('last_name')
          if first_name and last_name and first_name.lower() == last_name.lower():
              raise ValidationError('First and last names must be different.',
                                    code='invalid')
          return attrs
  </code></pre>
  <p>If I do this, then Django REST Framework handles the exception just fine:</p>
  <p><a href="https://i.stack.imgur.com/rm6KY.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/rm6KY.jpg" alt="enter image description here" /></a></p>
  <p>Here (finally ;-) are my questions:</p>
  <blockquote>
  <p>Why do I have to perform <strong>object-level</strong> validation in <em>both</em> the model and the serializer when I only have to do <strong>field-level</strong> validation in the model and the serializer will handle the exceptions just fine?</p>
  <p>Is this how Django REST Framework is intended to behave? Seems like the serializer should be able to gracefully handle <em>all</em> <code>ValidationError</code>s raised by the model.</p>
  </blockquote>