Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework & model validation

Tags:

Getting started using django-rest-framework, and I'm having some trouble regarding validation.

I have a basic model, and i've applied validators to a copple of its fields (A regular MaxLengthValidator and a custom RegexValidator, ending up with something like this:

class ZipCodeValidator(RegexValidator):     regex = '^([0-9]{5})$'     message = u'Invalid ZipCode.'   class User(AbstractUser, BaseUser):     """     Custom user model     """      # ... other fields ...     zipcode = models.CharField(         max_length=5, blank=True, validators=[ZipCodeValidator()]     )     description = models.TextField(         null=True, blank=True, max_length=1000, validators=[MaxLengthValidator(1000)]     ) 

I then created a ModelSerializer mapped to this model, with a few additional fields and methods. This is all served by a very simple `RetrieveUpdateAPIView.

I'm noticing that the validators are not called (i can enter anything in the zipcode field, or exceed 1000 characters for the description).

Quick and dirty solution has been to override the two fields at the serializer level and assigne them the validator there:

class UserSerializer(serializers.ModelSerializer):     zipcode = serializers.WritableField(         source='zipcode', required=False, validators=[ZipCodeValidator()]     )     description = serializers.WritableField(         source='description', required=False, validators=[MaxLengthValidator(1000)]     ) 

This works fine, but i don't like it much. I'd rather have this validation occur at the model level to be safer (i wouldn't having mind custom or additional validation on the serializer, but those rules will need to be enforced in all cases). Since serializers work a lot like django forms, i expected them to call the model's clean & cie method before saving them, but a quick look at the source seems to indicate it does not.

This is a bit annoying, it forces me to duplicate much of the fields code if I want to ensure the validation always happens, and i'd rather keep this as DRY as possible.

I might be missing something, but is there a nice and clean way to ensure those validators will be run by the serializer before updating the model ?

EDIT: Doubled checked the source, turns out that the instance's full_clean method is indeed called by the view before saving it to the db, which in turns ends up running the model's validator. Still lost as to why those don't seem to run, tho.

like image 717
astrognocci Avatar asked Apr 16 '14 09:04

astrognocci


People also ask

What is Django REST framework?

Django REST framework is a powerful and flexible toolkit for building Web APIs. Some reasons you might want to use REST framework: The Web browsable API is a huge usability win for your developers. Authentication policies including packages for OAuth1a and OAuth2.

What is difference between Django and Django REST framework?

Django is the web development framework in python whereas the Django Rest Framework is the library used in Django to build Rest APIs. Django Rest Framework is especially designed to make the CRUD operations easier to design in Django. Django Rest Framework makes it easy to use your Django Server as an REST API.

Which Django use REST framework?

337 companies reportedly use Django REST framework in their tech stacks, including Robinhood, UpstageAI, and BirdView.

Is Django GOOD FOR REST API?

Django REST framework (DRF) is a powerful and flexible toolkit for building Web APIs. Its main benefit is that it makes serialization much easier. Django REST framework is based on Django's class-based views, so it's an excellent option if you're familiar with Django.


1 Answers

This works for me:

class ZipCodeValidator(RegexValidator):     regex = r'^[0-9]{5}$'     message = 'Invalid ZipCode.'   class MyModel(models.Model):     zipcode = models.CharField(max_length=5, blank=True, validators=[ZipCodeValidator()])   class MyModelSerializer(serializers.ModelSerializer):     class Meta:         model = MyModel   >>> s1 = MyModelSerializer(data={'zipcode': '34234'}) >>> s1.is_valid() True >>> s2 = MyModelSerializer(data={'zipcode': 'f3434'}) >>> s2.is_valid() False >>> s2.errors {'zipcode': [u'Invalid ZipCode.']} 
like image 67
Norman8054 Avatar answered Oct 05 '22 22:10

Norman8054