Does a ModelSerializer catch "django.core.exceptions.ValidationError"s and turn them to an HTTP response with a 400 status code?

Let's say this is my model:

from django.core.exceptions import ValidationError


class MyModel(models.Model):
    value = models.CharField(max_length=255)

    def clean(self):
        if self.value == "bad":
            raise ValidationError("bad value")

    def save(self):
        self.full_clean()
        return super().save()

And I have this serializer:

from rest_framework.serializers import ModelSerializer

class MyModelSerializer(ModelSerializer):
    class Meta:
        model = MyModel
        fields = ["value"]

And this was my viewset

from rest_framework.viewsets import ModelViewSet

class MyModelViewSet(ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

My question is: what should happen when a bad value is submitted for value?

  • Should it be caught by DRF and turned into an HTTP response with a 400 status code?

  • Or should it be treated like a regular exception and crash the server?

I'm asking this because when I submit invalid data in DRF's browsable API, instead of catching the ValidationError and returning an HTTP response, DRF stops the application entirely.

Is that normal, or am I doing something wrong?

I don't want to repeat my validation logic again in the serializer, so what's the correct approach here?

I assume there are a few stimulus requests being used to test this:

  1. "good"
  2. "bad"
  3. "x" * 256 # greater than max_length
    if self.value == "bad":
        raise ValidationError("bad value")

The OP does not explicitly mention it, but I'm going to assume that test case (2.) does in fact trigger that raise, and Django turns it into a "client error" 400 http response. If you were to add a logging statement within the if, we should see a log entry prior to the raise happening.

when I submit invalid data in DRF's browsable API

I assume "invalid" is the "too long" test case (3.)

DRF stops the application entirely.

That is not normal, as the webserver should continue to listen and serve requests no matter what. The OP does not include a stack trace, so it is impossible to tell where the error originated. Django should trap whatever the exception was and return a "server error" 500 response to the web client, and append an entry to its local error log file.

I don't want to repeat my validation logic again

Indeed. Keep it DRY!

The code you posted looks good. There's something in your environment you're not telling us about, perhaps in your settings.py. Posting a GitHub repo link can be helpful, but posting a full stack trace is essential when tracking down such errors.

Please verify that you have not set DEBUG = True. I assume you're reporting bad behavior that happened in a production environment.

Вернуться на верх