在 DRF ModelViewSet 上创建用户时的自定义错误消息
Custom error message on Create User on DRF ModelViewSet
我正在使用 Django Rest Framework 编写 Django Rest API,其中我有一个基本自定义用户 User
和两种继承自 User
的用户,Doctor
和 Pacient
.
每个人都有不同的端点,因此要创建一个 Doctor
,我们向 /api/v1/doctor
发出一个 POST
请求并创建一个 Paciente
,一个 POST
到 api/v1/pacient/
.
如果我尝试创建一个用户(使用这些端点)但使用已经注册的电子邮件(我已将 Django 更改为使用电子邮件),我会得到以下信息。
{
"email": [
"user with this email already exists."
]
}
我想要实现的是更改此错误消息,但不仅要更改,我还需要验证电子邮件是来自 Pacient
还是 Doctor
,无论是哪个我正在使用的端点,因此我可以针对每种情况显示不同的消息。
PacientViewSet
(DoctorViewSet基本一样):
class PacientViewSet(viewsets.ModelViewSet):
serializer_class = PacientSerializer
queryset = Pacient.objects.all()
permission_classes = (AllowAny, )
序列化器:
class PacientSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = Paciente.objects.create_paciente_user(
nome_completo=self.validated_data['full_name'],
password=self.validated_data['password'],
email=self.validated_data['email'],
)
return user
class Meta:
model = Pacient
fields = ('id', 'email', 'password', 'full_name', ...)
extra_kwargs = {
'password': {
'write_only': True,
}
}
如果还有什么需要分享的,请告诉我。
编辑:
class CustomUser(AbstractBaseUser, PermissionsMixin):
full_name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(_('email address'), unique=True)
SEX_CHOICES = [
(ConstantesSexo.MALE, 'Male'),
(ConstantesSexo.FEMALE, 'Female'),
]
sex = models.CharField(max_length=1, choices=SEX_CHOICES, null=True, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False)
is_active = models.BooleanField(_('active'), default=True)
created = models.DateTimeField(_('date joined'), default=timezone.now)
modified = models.DateTimeField(auto_now=True)
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_('username'),
max_length=150,
unique=True,
blank=True,
null=True,
validators=[username_validator],
error_messages={
'unique': _("Username already exists."),
},
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
USER_CHOICES = [
(UserType.DOCTOR, 'Doctor'),
(UserType.PACIENT, 'Pacient'),
]
user_type = models.CharField(max_length=3, choices=USER_CHOICES)
class Pacient(CustomUser):
nome_social = models.CharField(blank=True, null=True, max_length=50)
class Doctor(CustomUser):
doctor_id = models.CharField(max_length=50)
bio = models.TextField(blank=True, null=True)
verified = models.DateTimeField(null=True, blank=True)
据我所知,有两种方法可以实现此目的
第一个会在 PacientSerializer
create
方法中引发错误
class PacientSerializer(serializers.ModelSerializer):
def create(self, validated_data):
if Paciente.objects.filter(email=validated_data["email"]).exists():
raise serializers.ValidationError("Your Custom Error Message")
user = Paciente.objects.create_paciente_user(
nome_completo=validated_data["full_name"],
password=validated_data["password"],
email=validated_data["email"],
)
return user
另一种方法是覆盖
def finalize_response(self, request, response, *args, **kwargs):
# change response.data dictionary accordingly
...
return response
最后我通过覆盖 ModelViewSet 中的 create 方法(而不是在序列化程序中)解决了这个问题:
class DoctorViewSet(viewsets.ModelViewSet):
def create(self, request, *args, **kwargs):
email = request.data.get('email')
user = CustomUser.objects.filter(email=email).first()
if email and user:
if user.is_doctor():
error_msg = 'doctor error msg'
elif user.is_pacient():
error_msg = 'pacient error msg'
return Response({'error': error_msg}, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
我知道这是一个老问题,我一直在尝试找到一个答案来更改电子邮件地址的唯一错误消息,但答案对于这么小的更改来说工作量太大,所以我调试了验证流程框架并提出了这个解决方案。我把它留在这里给寻找解决方案的人
我正在使用 dj_rest_auth 所以我有一个自定义注册序列化程序,它从 dj_rest_auth.registration.serializers.RegisterSerializer 扩展而来
所以我只需要在我的自定义序列化程序中覆盖以下方法,它就会按预期工作,它会覆盖唯一电子邮件的错误消息
def validate_email(self, email):
try:
email = super(CustomRegisterSerializer, self).validate_email(email);
except Exception as e:
raise serializers.ValidationError(
_("Please try a different email."))
return email
dj_rest_auth.registration.serializers.RegisterSerializer 有这个方法,我们正在重写以仅更改错误消息,我们也可以在其中添加我们自己的代码,但我只需要更改错误。
我发现的另一种方法是向我拥有的这个自定义序列化器添加一个 class 级别字段,即
email = serializers.EmailField(validators=[UniqueValidator(queryset=User.objects.all(),message="Please try a different email.")])
但是这个 运行 是一个额外的查询 User.objects.all()
所以想象一下有很多记录然后这可能会减慢响应速度
我正在使用 Django Rest Framework 编写 Django Rest API,其中我有一个基本自定义用户 User
和两种继承自 User
的用户,Doctor
和 Pacient
.
每个人都有不同的端点,因此要创建一个 Doctor
,我们向 /api/v1/doctor
发出一个 POST
请求并创建一个 Paciente
,一个 POST
到 api/v1/pacient/
.
如果我尝试创建一个用户(使用这些端点)但使用已经注册的电子邮件(我已将 Django 更改为使用电子邮件),我会得到以下信息。
{
"email": [
"user with this email already exists."
]
}
我想要实现的是更改此错误消息,但不仅要更改,我还需要验证电子邮件是来自 Pacient
还是 Doctor
,无论是哪个我正在使用的端点,因此我可以针对每种情况显示不同的消息。
PacientViewSet
(DoctorViewSet基本一样):
class PacientViewSet(viewsets.ModelViewSet):
serializer_class = PacientSerializer
queryset = Pacient.objects.all()
permission_classes = (AllowAny, )
序列化器:
class PacientSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = Paciente.objects.create_paciente_user(
nome_completo=self.validated_data['full_name'],
password=self.validated_data['password'],
email=self.validated_data['email'],
)
return user
class Meta:
model = Pacient
fields = ('id', 'email', 'password', 'full_name', ...)
extra_kwargs = {
'password': {
'write_only': True,
}
}
如果还有什么需要分享的,请告诉我。
编辑:
class CustomUser(AbstractBaseUser, PermissionsMixin):
full_name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(_('email address'), unique=True)
SEX_CHOICES = [
(ConstantesSexo.MALE, 'Male'),
(ConstantesSexo.FEMALE, 'Female'),
]
sex = models.CharField(max_length=1, choices=SEX_CHOICES, null=True, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False)
is_active = models.BooleanField(_('active'), default=True)
created = models.DateTimeField(_('date joined'), default=timezone.now)
modified = models.DateTimeField(auto_now=True)
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_('username'),
max_length=150,
unique=True,
blank=True,
null=True,
validators=[username_validator],
error_messages={
'unique': _("Username already exists."),
},
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
USER_CHOICES = [
(UserType.DOCTOR, 'Doctor'),
(UserType.PACIENT, 'Pacient'),
]
user_type = models.CharField(max_length=3, choices=USER_CHOICES)
class Pacient(CustomUser):
nome_social = models.CharField(blank=True, null=True, max_length=50)
class Doctor(CustomUser):
doctor_id = models.CharField(max_length=50)
bio = models.TextField(blank=True, null=True)
verified = models.DateTimeField(null=True, blank=True)
据我所知,有两种方法可以实现此目的
第一个会在 PacientSerializer
create
方法中引发错误
class PacientSerializer(serializers.ModelSerializer):
def create(self, validated_data):
if Paciente.objects.filter(email=validated_data["email"]).exists():
raise serializers.ValidationError("Your Custom Error Message")
user = Paciente.objects.create_paciente_user(
nome_completo=validated_data["full_name"],
password=validated_data["password"],
email=validated_data["email"],
)
return user
另一种方法是覆盖
def finalize_response(self, request, response, *args, **kwargs):
# change response.data dictionary accordingly
...
return response
最后我通过覆盖 ModelViewSet 中的 create 方法(而不是在序列化程序中)解决了这个问题:
class DoctorViewSet(viewsets.ModelViewSet):
def create(self, request, *args, **kwargs):
email = request.data.get('email')
user = CustomUser.objects.filter(email=email).first()
if email and user:
if user.is_doctor():
error_msg = 'doctor error msg'
elif user.is_pacient():
error_msg = 'pacient error msg'
return Response({'error': error_msg}, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
我知道这是一个老问题,我一直在尝试找到一个答案来更改电子邮件地址的唯一错误消息,但答案对于这么小的更改来说工作量太大,所以我调试了验证流程框架并提出了这个解决方案。我把它留在这里给寻找解决方案的人
我正在使用 dj_rest_auth 所以我有一个自定义注册序列化程序,它从 dj_rest_auth.registration.serializers.RegisterSerializer 扩展而来 所以我只需要在我的自定义序列化程序中覆盖以下方法,它就会按预期工作,它会覆盖唯一电子邮件的错误消息
def validate_email(self, email):
try:
email = super(CustomRegisterSerializer, self).validate_email(email);
except Exception as e:
raise serializers.ValidationError(
_("Please try a different email."))
return email
dj_rest_auth.registration.serializers.RegisterSerializer 有这个方法,我们正在重写以仅更改错误消息,我们也可以在其中添加我们自己的代码,但我只需要更改错误。
我发现的另一种方法是向我拥有的这个自定义序列化器添加一个 class 级别字段,即
email = serializers.EmailField(validators=[UniqueValidator(queryset=User.objects.all(),message="Please try a different email.")])
但是这个 运行 是一个额外的查询 User.objects.all()
所以想象一下有很多记录然后这可能会减慢响应速度