I had a lot of trouble recently implementing a User and related objects
using the django.contrib.auth get_user_model() within the DRF. Much of my
trouble came from migrating from DRF 2.3.x to 3.3.3. I found myself in a
spot where my password was being stored in plaintext in the database, even
though my UserSerializer class create looked as follows
class UserSerializer(serializers.ModelSerializer):
...
def create(self,validated_data):
survey_id = self.initial_data['profile']['survey_id']
user = get_user_model().objects.create(**validated_data)
user.set_password(validated_data['password'])
user.save()
saved_profile =
Profile.objects.create(user=user,survey_id=survey_id)
Collection.objects.create(creator=saved_profile)
Token.objects.create(user=user)
return user
...
and in my views.py, I had a perform_create method, roughly as follows
class UserCreateView(CreateAPIView):
model = get_user_model()
serializer_class = UserSerializer
def perform_create(self,serializer):
serializer.save(rando_user_attribute=self.get_rando_attribute(arg))
I had this because it wasn't clear to me if perform_create replaced
pre_save or post_save in DRF 2.x.
For the case I illustrate above, we should be able to quickly see how I
ended up with plaintext passwords in my database:
Even though the serializer class was creating hte User object and calling
that instance's set_password() method, when the serializer's create()
method returned to perform_create, the serializer.save() method was
clobbering the instance data with effectively stale data from data the
serializer instance had before the serializer class's create() method was
called. So password was being set back to what the serializer class would
have had for validated_data['password'].
So the docs are write, this does replace pre_save and post_save, just not
in a very clear way. In fact, it's more like post_save using pre_save data.
Arrgh.
My own recco for the docs is to be clear that this perform_create really
replaces post_save(), and one should be careful using serializer.save()
within perform_create() because it might save data back to your model
instance that had not been intended to be saved without some prior
transformation. Alternatively, perhaps the docs should recco that the
serializer really just be there as a convenience for ingesting input data
and validation, and that actual db model instnace create() calls should be
placed only in the perform_create() method and that the serializer class
create() method should not hold such calls.
Thoughts?
Thanks,
Steve
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.