Django Rest Framework 自定义序列化程序的 ValidationError 不工作
Django Rest Framework custom serializer's ValidationError not working
我正在尝试在 Django 中设置自定义登录序列化程序并想要自定义响应,但默认响应始终显示:
{
"username":[
"This field is required."
],
"password":[
"This field is required."
]
}
我试着像这样设置我的序列化程序:
class MyLoginSerializer(serializers.Serializer):
username = serializers.CharField(required=True, allow_blank=True)
email = serializers.EmailField(required=False, allow_blank=True)
password = serializers.CharField(style={'input_type': 'password'})
def authenticate(self, **kwargs):
return authenticate(self.context['request'], **kwargs)
def _validate_email(self, email, password):
user = None
if email and password:
user = self.authenticate(email=email, password=password)
else:
msg = _('Must include "email" and "password".')
raise serializers.ValidationError(msg)
return user
def _validate_username(self, username, password):
print("in username")
user = None
if username and password:
print("in username 2")
try:
user = self.authenticate(username=username, password=password)
except Exception:
raise serializers.ValidationError("Wrong")
else:
print("in username 3")
msg = _('Must include "username" and "password".')
raise serializers.ValidationError(msg)
return user
def _validate_username_email(self, username, email, password):
user = None
if email and password:
user = self.authenticate(email=email, password=password)
elif username and password:
user = self.authenticate(username=username, password=password)
else:
msg = _(
'Must include either "username" or "email" and "password".'
)
raise serializers.ValidationError(msg)
return user
def validate(self, attrs):
username = attrs.get('username')
email = attrs.get('email')
password = attrs.get('password')
user = None
if 'allauth' in settings.INSTALLED_APPS:
from allauth.account import app_settings
# Authentication through email
if (app_settings.AUTHENTICATION_METHOD ==
app_settings.AuthenticationMethod.EMAIL):
user = self._validate_email(email, password)
# Authentication through username
elif (app_settings.AUTHENTICATION_METHOD ==
app_settings.AuthenticationMethod.USERNAME):
user = self._validate_username(username, password)
# Authentication through either username or email
else:
user = self._validate_username_email(username, email, password)
else:
# Authentication without using allauth
if email:
try:
username = GameUser.objects\
.get(email__iexact=email)\
.get_username()
except UserModel.DoesNotExist:
pass
if username:
user = self._validate_username_email(username, '', password)
# Did we get back an active user?
if user:
if not user.is_active:
msg = ('User account is disabled.')
raise exceptions.ValidationError(msg)
else:
msg = ('Wrong login information.')
raise exceptions.ValidationError(msg)
# If required, is the email verified?
if 'rest_auth.registration' in settings.INSTALLED_APPS:
from allauth.account import app_settings
if app_settings.EMAIL_VERIFICATION == app_settings\
.EmailVerificationMethod\
.MANDATORY:
email_address = user.emailaddress_set.get(email=user.email)
if not email_address.verified:
raise serializers.ValidationError((
'E-mail is not verified.'
))
attrs['user'] = user
return attrs
我在 settings.py:
中将其设置为我的登录序列化程序
REST_AUTH_SERIALIZERS ={
'LOGIN_SERIALIZER': 'api.serializer.MyLoginSerializer'
}
这是我的自定义登录视图:
class CustomLoginView(LoginView):
permission_classes = (AllowAny,)
serializer_class = MyLoginSerializer
def get_response(self):
original_response = super().get_response()
print("ORIGINAL REESPONSE:")
print(str(self.user))
mydata = {"username": str(self.user), "status": "success"}
original_response.data.update(mydata)
return original_response
如何让它显示自定义 'Must include "email" and "password".'
而不是默认消息?
谢谢!
简短回答,使用序列化器验证数据,然后根据序列化器验证器自定义响应。您甚至可以使用案例。
此基本结构在您的 view/viewset 中实现,例如:
class MyViewSet(viewsets.ModelViewSet):
"""
My View Set
"""
queryset = #
serializer_class = #
# take which ever method you want to add the custom formatting to
# and modify it, or create a new method with its own special endpoint
def view_set_method_to_modify(self, *other_args):
# Do some stuff to keep the desired functions of the method you are hacking
serializer = serializers.MySerializer(data=request.data, context={"request": request})
if serializer.is_valid():
# Do some stuff with serializer.validated_data['my_var'])
return Response({'message': 'Yay the data is valid!!!'},
status=status.HTTP_200_OK)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
这是我更新用户密码的示例。我没有破解现有方法,而是添加了一个具有自己特殊端点的新方法。
views.py
class UserViewSet(viewsets.ModelViewSet):
"""
User View Set
"""
queryset = User.objects.all()
serializer_class = serializers.UserSerializer
@action(methods=['post'], detail=True,
url_path='change-password', url_name='change_password')
def set_password(self, request, pk=None):
user = self.get_object()
serializer = serializers.PasswordSerializer(data=request.data, context={"request": request})
if serializer.is_valid():
user.set_password(serializer.validated_data['new_password'])
user.save()
return Response({'message': 'password set'},
status=status.HTTP_200_OK)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
serializers.py
class PasswordSerializer(Serializer):
old_password = CharField(required=True)
new_password = CharField(required=True)
def validate(self, data):
request = self.context['request']
user = request.user
new_password = request.data['new_password']
old_password = request.data['old_password']
validate_passwords(old=old_password, new=new_password, user=user)
return data
我正在尝试在 Django 中设置自定义登录序列化程序并想要自定义响应,但默认响应始终显示:
{
"username":[
"This field is required."
],
"password":[
"This field is required."
]
}
我试着像这样设置我的序列化程序:
class MyLoginSerializer(serializers.Serializer):
username = serializers.CharField(required=True, allow_blank=True)
email = serializers.EmailField(required=False, allow_blank=True)
password = serializers.CharField(style={'input_type': 'password'})
def authenticate(self, **kwargs):
return authenticate(self.context['request'], **kwargs)
def _validate_email(self, email, password):
user = None
if email and password:
user = self.authenticate(email=email, password=password)
else:
msg = _('Must include "email" and "password".')
raise serializers.ValidationError(msg)
return user
def _validate_username(self, username, password):
print("in username")
user = None
if username and password:
print("in username 2")
try:
user = self.authenticate(username=username, password=password)
except Exception:
raise serializers.ValidationError("Wrong")
else:
print("in username 3")
msg = _('Must include "username" and "password".')
raise serializers.ValidationError(msg)
return user
def _validate_username_email(self, username, email, password):
user = None
if email and password:
user = self.authenticate(email=email, password=password)
elif username and password:
user = self.authenticate(username=username, password=password)
else:
msg = _(
'Must include either "username" or "email" and "password".'
)
raise serializers.ValidationError(msg)
return user
def validate(self, attrs):
username = attrs.get('username')
email = attrs.get('email')
password = attrs.get('password')
user = None
if 'allauth' in settings.INSTALLED_APPS:
from allauth.account import app_settings
# Authentication through email
if (app_settings.AUTHENTICATION_METHOD ==
app_settings.AuthenticationMethod.EMAIL):
user = self._validate_email(email, password)
# Authentication through username
elif (app_settings.AUTHENTICATION_METHOD ==
app_settings.AuthenticationMethod.USERNAME):
user = self._validate_username(username, password)
# Authentication through either username or email
else:
user = self._validate_username_email(username, email, password)
else:
# Authentication without using allauth
if email:
try:
username = GameUser.objects\
.get(email__iexact=email)\
.get_username()
except UserModel.DoesNotExist:
pass
if username:
user = self._validate_username_email(username, '', password)
# Did we get back an active user?
if user:
if not user.is_active:
msg = ('User account is disabled.')
raise exceptions.ValidationError(msg)
else:
msg = ('Wrong login information.')
raise exceptions.ValidationError(msg)
# If required, is the email verified?
if 'rest_auth.registration' in settings.INSTALLED_APPS:
from allauth.account import app_settings
if app_settings.EMAIL_VERIFICATION == app_settings\
.EmailVerificationMethod\
.MANDATORY:
email_address = user.emailaddress_set.get(email=user.email)
if not email_address.verified:
raise serializers.ValidationError((
'E-mail is not verified.'
))
attrs['user'] = user
return attrs
我在 settings.py:
中将其设置为我的登录序列化程序REST_AUTH_SERIALIZERS ={
'LOGIN_SERIALIZER': 'api.serializer.MyLoginSerializer'
}
这是我的自定义登录视图:
class CustomLoginView(LoginView):
permission_classes = (AllowAny,)
serializer_class = MyLoginSerializer
def get_response(self):
original_response = super().get_response()
print("ORIGINAL REESPONSE:")
print(str(self.user))
mydata = {"username": str(self.user), "status": "success"}
original_response.data.update(mydata)
return original_response
如何让它显示自定义 'Must include "email" and "password".'
而不是默认消息?
谢谢!
简短回答,使用序列化器验证数据,然后根据序列化器验证器自定义响应。您甚至可以使用案例。
此基本结构在您的 view/viewset 中实现,例如:
class MyViewSet(viewsets.ModelViewSet):
"""
My View Set
"""
queryset = #
serializer_class = #
# take which ever method you want to add the custom formatting to
# and modify it, or create a new method with its own special endpoint
def view_set_method_to_modify(self, *other_args):
# Do some stuff to keep the desired functions of the method you are hacking
serializer = serializers.MySerializer(data=request.data, context={"request": request})
if serializer.is_valid():
# Do some stuff with serializer.validated_data['my_var'])
return Response({'message': 'Yay the data is valid!!!'},
status=status.HTTP_200_OK)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
这是我更新用户密码的示例。我没有破解现有方法,而是添加了一个具有自己特殊端点的新方法。
views.py
class UserViewSet(viewsets.ModelViewSet):
"""
User View Set
"""
queryset = User.objects.all()
serializer_class = serializers.UserSerializer
@action(methods=['post'], detail=True,
url_path='change-password', url_name='change_password')
def set_password(self, request, pk=None):
user = self.get_object()
serializer = serializers.PasswordSerializer(data=request.data, context={"request": request})
if serializer.is_valid():
user.set_password(serializer.validated_data['new_password'])
user.save()
return Response({'message': 'password set'},
status=status.HTTP_200_OK)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
serializers.py
class PasswordSerializer(Serializer):
old_password = CharField(required=True)
new_password = CharField(required=True)
def validate(self, data):
request = self.context['request']
user = request.user
new_password = request.data['new_password']
old_password = request.data['old_password']
validate_passwords(old=old_password, new=new_password, user=user)
return data