serializer validate vs full_clean

382 views
Skip to first unread message

Jani Kajala

unread,
Sep 23, 2015, 2:02:43 PM9/23/15
to Django REST framework
Hi,

I'm struggling with the best practices related to new data validation of serializers. The guideline was to replace model clean() with serializer validate(). However, I don't see how to handle cases when there is need for the model.

A simple example: I have model which has email field. I would like allow API call to PATCH the email-field freely, but only if it's not already in use by someone else than the model itself. So how should I handle this in serializer validate() since it doesn't have access to the model? So I would allow PATCH with identical email what the model already has, and PATCH with new email if it's unused by any other model.

This is just an example so please don't rant about how email should be always confirmed etc. ;) Anyway, there are many examples where similar dependencies happen. For example, I could allow user to send money to other users (POST /transfer) but only if the sending user has been verified, etc., so there are definitely valid cases where pure input validation just doesn't cut it.

The second issue I have is that moving all the functionality to serializer breaks not only Django Admin, but it also breaks use of Django shell. It's extremely useful to able to clean/validate models which you're creating/updating in shell. Giving up model validation on Django shell and Admin seems heavy.

Anyway, as you can see, I'm just trying to follow recommended practices, so please let me know your thoughts and how you have solved similar issues.


Thanks!
Jani

Tom Christie

unread,
Sep 24, 2015, 6:34:50 AM9/24/15
to Django REST framework
> how should I handle this in serializer validate() since it doesn't have access to the model? So I would allow PATCH with identical email what the model already has, and PATCH with new email if it's unused by any other model.

You have serializer.instance available for updates, so you can check if an equivalent email also exists, with something like this:

    MyModel.filter(email=email).exclude(pk=serializer.instance.pk).exists()

Alternatively you can use something like `validators=UniqueValidator(queryset=MyModel.objects.all)` against the email field.


> it also breaks use of Django shell.

My take would typically be roughly: Have models raise assertion level or DB level errors (Ie your code is broken) if constraints are violated, and serializers for the ValidationError stuff (Ie this is a valid case of incorrect user input that we should report back)

Jani Kajala

unread,
Sep 25, 2015, 12:19:45 PM9/25/15
to Django REST framework
> You have serializer.instance available for updates, so you can check if an equivalent email also exists, with something like this:

Thanks, I didn't realize the instance was available!

Reply all
Reply to author
Forward
0 new messages