为什么使用 Django rest 框架 ModelSerializer。创建和 ModelSerializer.validate 无法正常工作?

why the Django rest framework ModelSerializer. create and ModelSerializer.validate not working properly?

我正在开发一个通过 Django rest 框架进行用户注册的身份验证系统。

serializers.py

from rest_framework import serializers
from .models import NewEmployeeProfile


class RegistrationSerializers(serializers.ModelSerializer):
    '''
    We need to add the password2, as its not the part of the NewEmployeeProfile model. So, we need to make it manually.
    '''
    password2 = serializers.CharField(style={'input_type: password'}, write_only=True)

    class Meta:
        model = NewEmployeeProfile
        fields = ('email', 'first_name', 'last_name', 'employee_code', 'contact', 'dob', 'password', 'password2')
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def create(self, validated_data):
        """
        before we save the new user, we need to make sure that the password1, and password2 matches. In order to do
        that, we need to override the save() method.
        """

        password = self.validated_data['password']
        password2 = self.validated_data['password2']

        if password != password2:
            raise serializers.ValidationError({'password': f'password must match..'})
        return NewEmployeeProfile.objects.create(**validated_data)

    def validate(self, attrs):
        if attrs:
            account = NewEmployeeProfile(
                email=self.validated_data['email'],
                first_name=self.validated_data['first name'],
                last_name=self.validated_data['last name'],
                employee_code=self.validated_data['employee code'],
                contact=self.validated_data['contact'],
                dob=self.validated_data['dob'],
            )
            account.save()
            return account

views.py

class UserRegisterView(ListCreateAPIView):
    create_queryset = NewEmployeeProfile.objects.all()
    serializer_class = RegistrationSerializers(create_queryset, many=True)
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = RegistrationSerializers(data=request.data)
        if serializer.is_valid():
            newUser = serializer.save()
            serializer = RegistrationSerializers(newUser)
            return Response(data={"status": "OK", "message": serializer.data}, status=status.HTTP_201_CREATED)
        return Response(data={"status": "error"}, status=status.HTTP_400_BAD_REQUEST)

models.py

from django.db import models
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, AbstractUser
from django.utils.translation import gettext_lazy as _


class AccountManager(BaseUserManager):
    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(email, password, **extra_fields)

    def create_user(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        if not email:
            raise ValueError(_('Enter the email before proceeding'))

        email = self.normalize_email(email)
        user = self.model(email=email, password=password, **extra_fields)
        user.set_password(password)
        user.save()
        return user


class NewEmployeeProfile(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    employee_code = models.CharField(max_length=10, null=True)
    contact = models.CharField(max_length=10, null=True)
    dob = models.DateField(blank=True, null=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )

    objects = AccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'contact']

    def __str__(self):
        return str(self.email)

问题是当我在 postman 中测试 API 时,它给出以下输出:

{
    "first_name": [
        "This field is required."
    ],
    "last_name": [
        "This field is required."
    ]
}

但是,在 POSTMAN 中测试 POST 方法时,我输入了所有数据。

截图:

在进行故障排除时,我发现在 serializers.py 中的“创建”函数中我没有返回任何内容。所以,我添加了

return NewEmployeeProfile.objects.create(**validated_data)

现在,当我测试我的 API 时,POST 提交进入无限循环,在 POSTMAN 'body'.[=20= 中没有输出]

我想,我没有正确覆盖“创建”和“验证”方法。

app.urls
from django.urls import path
from .views import signupView, UserRegisterView

urlpatterns = [
    path('signup/', signupView, name='signup'),
    path('register/', UserRegisterView.as_view(), name='register'),
    ]

project.url

urlpatterns = [
    path('admin/', admin.site.urls),
    path('apii/', include('AUTHENTICATION.urls')),
]

新错误:

Bad Request: /apii/register/
[05/Apr/2021 11:17:48] "POST /apii/register/ HTTP/1.1" 400 82

试试这个,

from django.contrib.auth.hashers import make_password

def create(self, validated_data):
    validated_data["password"] = make_password(validated_data["password"])
    super().create(validated_data)

def validate(self, attrs):
    if attrs.get("password") != attrs.pop("password2"):
        raise serializers.ValidationError({"password": f"password must match.."})
    return super().validate(attrs)

此外,表单数据中名字和姓氏的键必须是 first_namelast_name.

更新 #1:

def create(self, validated_data):
    validated_data["password"] = make_password(validated_data["password"])
    return super().create(validated_data) # forgot the return here.

def validate(self, attrs):
    if attrs.get("password") != attrs.pop("password2"):
        raise serializers.ValidationError({"password": f"password must match.."})
    return super().validate(attrs)

# Also update the view
class UserRegisterView(ListCreateAPIView):
    create_queryset = NewEmployeeProfile.objects.all()
    serializer_class = RegistrationSerializers
    permission_classes = [AllowAny]

    # A custom create method is not required

我认为问题出在邮递员请求中发送的密钥

我认为应该是 first_namelast_name 而不是 first namelast name