django - 为什么要使用 Django REST 框架 ModelSerializer。创建和 ModelSerializer.validate 不能正常工作?
问题描述
我正在开发一个通过 Django rest 框架进行用户注册的身份验证系统。
序列化程序.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
视图.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)
模型.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)
问题是当我在邮递员中测试 API 时,它会给出以下输出:
{
"first_name": [
"This field is required."
],
"last_name": [
"This field is required."
]
}
但是,在 POSTMAN 中测试 POST 方法时,我输入了所有数据。
截屏:
在进行故障排除时,我发现在“create”函数内的 serializers.py 中我什么也没返回。所以,我补充说
return NewEmployeeProfile.objects.create(**validated_data)
现在,当我测试我的 API 时,POST 提交进入无限循环,在 POSTMAN 的“正文”中没有输出。
我想,我没有正确覆盖“创建”和“验证”方法。
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'),
]
项目.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_name和last_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
推荐阅读
- unix - 将日志附加到 unix 中的文件,但每天使用不同的名称
- swift - (Swift) 嵌套函数,函数作为返回,参数
- python - 如何在 Django 管理站点中显示 django-simple-history 的历史表?
- ruby - 减少来自 Includes assoc 的 SQL 查询
- r - 在 Shiny 中获取当前输入值列表的问题
- django - Django 序列化器 ManyToMany 重新运行名称数组而不是 ID 数组
- neo4j - Cypher:嵌套 FOREACH 构建“实数树”。问题是使更深的循环有条件,因此较小的数字精度更高
- python - 如何绘制累积分布函数?
- layout - 使用 cos-bilkent 布局的 randomize=false 的真正含义是什么
- java - 将 maven 设置为具有框架和使用它的其他项目