0

I am trying to print out the list of validators in django rest framework, however when I print it out it seem like it is always empty.

Here is a part of the code

class AccountViewSet(viewsets.ModelViewSet):
    lookup_field = 'username'
    queryset = Account.objects.all()
    serializer_class = AccountSerializer


    def create(self, request):

        serializer = self.serializer_class(data=request.data)
        # this always return []
        print serializer.validators

This is counterintuitive because when I tested invalid data in request.data , the code clearly runs the validator since is_valid() return error as the documentation indicates. Therefore it doesn't make sense that I can observe the validator taking effect but can't print it out. Can someone point out what I am missing?

Thanks

4
  • I don't think there is a validators attribute. Did you try get_validators()? Also, I usually find what I need to know from reading the source. github.com/tomchristie/django-rest-framework/blob/master/… Commented Aug 27, 2015 at 3:48
  • I think validators are in this line for validator in self.validators: in line 488, I tried get_validators after you mentioned it, and still got [] when I print it out, which is weird because I can see that when I pass invalid data in it will return errors Commented Aug 27, 2015 at 3:52
  • Yes, but this is a Field objects, not a Serializer object. Commented Aug 27, 2015 at 17:05
  • Basic serializer inherits Field in class BaseSerializer(Field): line 58 , I also checked the serializer class, it seems like there is no validator besides the one inherited from Field? Commented Aug 27, 2015 at 17:07

2 Answers 2

3

Why serializer.validators returns [] in your case?

This is happening because you have not passed a validators arguments to the serializer when creating an instance of the serializer. Had you passed the validators argument, then serializer._validators would be set to that value. Then, if you check serializer.validators, it would give you the list of validators passed.

For Example:

In [1]: serializer = SomeSerializer(data=some_data, validators=[validator1, validator2])

In [2]: serializer.validators
Out [2]: [validator1, validator2] # gives the list of validators

By default, [] is returned if no validators is passed when accessing serializer.validators.

Source code for reference:

Now, BaseSerializer inherits from Field class which calls its __init__().

class BaseSerializer(Field):

    def __init__(self, instance=None, data=empty, **kwargs):
        ...
        super(BaseSerializer, self).__init__(**kwargs)

Here, default_validators is an empty list [].

class Field(object):

    default_validators = [] # an empty list by default
    default_empty_html = empty
    initial = None

    def __init__(self, read_only=False, write_only=False,
                 required=None, default=empty, initial=empty, source=None,
                 label=None, help_text=None, style=None,
                 error_messages=None, validators=None, allow_null=False):

        ...

        # Here, it checks if validators argument was passed when creating the serializer instance
        # If you have passed, then `.validators` will be set to that value.
        if validators is not None:
            self.validators = validators[:]

        ...

    @property
    def validators(self):
        if not hasattr(self, '_validators'): 
            # This will be executed as there was no validators passed in kwargs
            self._validators = self.get_validators()
        return self._validators

    @validators.setter
    def validators(self, validators):
        self._validators = validators


    def get_validators(self):
        return self.default_validators[:] # returns empty list

Why your code shows error for invalid data then?

This is because field-level validators are causing that error. Your serializer-level validators is [] but there are some field-level validators which are raising error for invalid data.

To see field-level validators, you can do print repr(serializer).

Sign up to request clarification or add additional context in comments.

Comments

1

From http://www.django-rest-framework.org/api-guide/validators/

Validation in REST framework

Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class.

With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:

  • It introduces a proper separation of concerns, making your code behavior more obvious.
  • It is easy to switch between using shortcut ModelSerializer classes and using explicit Serializer classes. Any validation behavior being used for ModelSerializer is simple to replicate.
  • Printing the repr of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.

When you're using ModelSerializer all of this is handled automatically for you. If you want to drop down to using a Serializer classes instead, then you need to define the validation rules explicitly.

Example

As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.

class CustomerReportRecord(models.Model):
    time_raised = models.DateTimeField(default=timezone.now, editable=False)
    reference = models.CharField(unique=True, max_length=20)
    description = models.TextField()

Here's a basic ModelSerializer that we can use for creating or updating instances of CustomerReportRecord:

class CustomerReportSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomerReportRecord

If we open up the Django shell using manage.py shell we can now

>>> from project.example.serializers import CustomerReportSerializer
>>> serializer = CustomerReportSerializer()
>>> print(repr(serializer))
CustomerReportSerializer():
    id = IntegerField(label='ID', read_only=True)
    time_raised = DateTimeField(read_only=True)
    reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>])
    description = CharField(style={'type': 'textarea'})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.