简体   繁体   English

django rest 框架使用密码创建用户

[英]django rest framework create user with password

Using django-rest-framework 3 and django 1.8使用 django-rest-framework 3 和 django 1.8

I am trying to create a user using django-rest-framework ModelViewSerializer.我正在尝试使用 django-rest-framework ModelViewSerializer 创建一个用户。 problem is that the default objects.create method used by DRF leave the password as plain text.问题是 DRF 使用的默认 objects.create 方法将密码保留为纯文本。

The problem is that DRF serialzer create method is using objects.create querysets/#create method instead of using objects.create_user method.问题是 DRF 序列化器创建方法使用objects.create querysets/#create方法而不是使用objects.create_user方法。

code from serializers.py line 775来自serializers.py第 775 行的代码

instance = ModelClass.objects.create(**validated_data)

What is the best solution for this?什么是最好的解决方案? i can override the serializer.create method to use objects.user_create instead of objects.create but it does not feel like the right solution.我可以覆盖 serializer.create 方法以使用 objects.user_create 而不是 objects.create ,但感觉这不是正确的解决方案。

rest of code:其余代码:

from django.contrib.auth.models import User
from rest_framework import viewsets

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'email','password')
        write_only_fields = ('password',)


class UserViewSet(viewsets.ModelViewSet):   
    queryset = User.objects.all()
    serializer = UserSerializer()

you can override create in UserSerializer:您可以在 UserSerializer 中覆盖create

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其他解决方案可以覆盖 ViewSet 类中的perform_create或者您可以在视图集类中编写自己的create方法

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:更新: @freethebees 评论后,覆盖perform_create也有效,所以这里是代码片段:

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注意:此答案提供了 3 种解决方案,选择您认为更适合您的需求和项目生态系统的解决方案

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)注意 2我个人更喜欢在UserViewSet (第二个代码片段)中覆盖create ,因为在那里您可以简单地返回您的自定义Response (例如在登录后返回用户配置文件)

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.除了@aliva 的答案,您错过了serializers.Modelserializer.create()的功能serializers.Modelserializer.create()保留它可能非常好,例如处理多对多关系),还有一种方法可以保留它。

By using the user.set_password() method, the password can also be correctly set, like:通过使用user.set_password()方法,也可以正确设置密码,例如:

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 :-).决定哪种权衡对您更重要:-)。

See documentation for set_password .请参阅有关set_password 的文档。

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)

A complete example that support POST and PUT / PATCH without another SQL UPDATE statement.支持POSTPUT / PATCH完整示例,无需其他 SQL UPDATE 语句。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM