django rest framework create user with password

后端 未结 4 781
说谎
说谎 2021-02-07 13:37

Using django-rest-framework 3 and django 1.8

I am trying to create a user using django-rest-framework ModelViewSerializer. problem is that the default objects.create m

相关标签:
4条回答
  • 2021-02-07 13:56

    you can override create in UserSerilizer:

    class UserSerializer(serializers.ModelSerializer):
        # ....
    
        def create(self, validated_data):
            user = User.objects.create_user(**validated_data)
            return user
    

    other solutions can be overriding perform_create in ViewSet class or you can write your own create method in your viewset class

    class UserViewSet(viewsets.ModelViewSet): 
        def create(self, request, format=None):
            # create user here
            # do not call seriailzer.save()
    

    UPDATE: after @freethebees commented, overriding perform_create also works, so here is the code snippet:

    class UserViewSet(viewsets.ModelViewSet, mixins.CreateModelMixin): 
        def perform_create(self, serializer):
            # use User.objects.create_user to create user
            pass
    

    NOTE: this answer gives 3 solutions, choose the one you think it better fits your needs and your project's ecosystem

    NOTE 2 I personally prefer overriding create in UserViewSet (second code snippet) because there you can simply return your custom Response (for example return user profile after login)

    0 讨论(0)
  • 2021-02-07 14:05

    A complete example that support POST and PUT/PATCH without another SQL UPDATE statement.

    class MyUserSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.User
            fields = '__all__'
    
        def create(self, validated_data):
            if "password" in validated_data:
                from django.contrib.auth.hashers import make_password
                validated_data["password"] = make_password(validated_data["password"])
            return super().create(validated_data)
    
        def update(self, instance, validated_data):
            if "password" in validated_data:
                from django.contrib.auth.hashers import make_password
                validated_data["password"] = make_password(validated_data["password"])
            return super().update(instance, validated_data)
    
    0 讨论(0)
  • 2021-02-07 14:10

    In addition to @aliva's answer where you miss out on the functionalities in serializers.Modelserializer.create() (which could be quite nice to preserve, for example handling of many-to-many relations), there is a way to keep this.

    By using the user.set_password() method, the password can also be correctly set, like:

    class UserSerializer(serializers.ModelSerializer):
    
        def create(self, validated_data):
            user = super().create(validated_data)
            user.set_password(validated_data['password'])
            user.save()
            return user
    

    This has the benefit of keeping the super class' functionality, but the downside of an additional write to the database. Decide which trade-off is more important to you :-).

    Edit: Fix syntax error

    Edit2: jkatzer's comment makes a lot of sense. I don't have the environment set up at the moment to look at it, and i also don't recall if there was more changes I'd made to this solution that did not put in the post. But looking at it now I'm agreeing with this comment, should probably do something more in the lines of Alwx's answer....

    0 讨论(0)
  • 2021-02-07 14:13

    There is even better option to validate password in serializer

    from django.contrib.auth.hashers import make_password
    
    class UserSerializer(serializers.ModelSerializer):
        def validate_password(self, value: str) -> str:
            return make_password(value)
    
    0 讨论(0)
提交回复
热议问题