如何将字段的验证错误以json的形式从at传给React的django序列化器

问题描述 投票:0回答:1

在我的rest框架用户注册表中,我成功创建了一个自定义注册表,并添加了一些验证器。它在rest框架中显示了相应的验证错误.但是当通过redux把这个链接到react中时,它得到了错误,但没有显示相应的验证错误,如" A user is already registered with this e-mail address. ".其余的则显示为:"A user is already registered with this e-mail address. 这个.

得到反应的JSON格式是这样的

error: {
    message: 'Request failed with status code 400',
    name: 'Error',
    fileName: 'http://localhost:3000/static/js/1.chunk.js',
    lineNumber: 871,
    columnNumber: 15,
    stack: 'createError@http://localhost:3000/static/js/1.chunk.js:871:15\nsettle@http://localhost:3000/static/js/1.chunk.js:1092:12\nhandleLoad@http://localhost:3000/static/js/1.chunk.js:346:13\nEventHandlerNonNull*dispatchXhrRequest@http://localhost:3000/static/js/1.chunk.js:322:5\nxhrAdapter@http://localhost:3000/static/js/1.chunk.js:301:10\ndispatchRequest@http://localhost:3000/static/js/1.chunk.js:924:10\npromise callback*request@http://localhost:3000/static/js/1.chunk.js:712:23\nforEachMethodWithData/Axios.prototype[method]@http://localhost:3000/static/js/1.chunk.js:736:17\nwrap@http://localhost:3000/static/js/1.chunk.js:1252:15\nsignUp/<@http://localhost:3000/static/js/main.chunk.js:3406:50\ncreateThunkMiddleware/</</<@http://localhost:3000/static/js/1.chunk.js:40096:18\ndispatch@http://localhost:3000/register:1:28546\nonAuth@http://localhost:3000/static/js/main.chunk.js:3305:110\nRegMain/this.handlesubmit@http://localhost:3000/static/js/main.chunk.js:2684:62\ncallCallback@http://localhost:3000/static/js/1.chunk.js:8030:18\ninvokeGuardedCallbackDev@http://localhost:3000/static/js/1.chunk.js:8079:20\ninvokeGuardedCallback@http://localhost:3000/static/js/1.chunk.js:8132:35\ninvokeGuardedCallbackAndCatchFirstError@http://localhost:3000/static/js/1.chunk.js:8147:29\nexecuteDispatch@http://localhost:3000/static/js/1.chunk.js:8232:46\nexecuteDispatchesInOrder@http://localhost:3000/static/js/1.chunk.js:8257:24\nexecuteDispatchesAndRelease@http://localhost:3000/static/js/1.chunk.js:11141:33\nexecuteDispatchesAndReleaseTopLevel@http://localhost:3000/static/js/1.chunk.js:11150:14\nforEachAccumulated@http://localhost:3000/static/js/1.chunk.js:11122:12\nrunEventsInBatch@http://localhost:3000/static/js/1.chunk.js:11167:25\nrunExtractedPluginEventsInBatch@http://localhost:3000/static/js/1.chunk.js:11377:23\nhandleTopLevel@http://localhost:3000/static/js/1.chunk.js:11421:40\nbatchedEventUpdates$1@http://localhost:3000/static/js/1.chunk.js:29567:16\nbatchedEventUpdates@http://localhost:3000/static/js/1.chunk.js:8639:16\ndispatchEventForLegacyPluginEventSystem@http://localhost:3000/static/js/1.chunk.js:11431:28\nattemptToDispatchEvent@http://localhost:3000/static/js/1.chunk.js:12151:48\ndispatchEvent@http://localhost:3000/static/js/1.chunk.js:12072:45\nunstable_runWithPriority@http://localhost:3000/static/js/1.chunk.js:41893:16\nrunWithPriority$1@http://localhost:3000/static/js/1.chunk.js:18917:14\ndiscreteUpdates$1@http://localhost:3000/static/js/1.chunk.js:29584:16\ndiscreteUpdates@http://localhost:3000/static/js/1.chunk.js:8652:16\ndispatchDiscreteEvent@http://localhost:3000/static/js/1.chunk.js:12051:22\nEventListener.handleEvent*addEventBubbleListener@http://localhost:3000/static/js/1.chunk.js:11905:15\ntrapEventForPluginEventSystem@http://localhost:3000/static/js/1.chunk.js:12045:31\ntrapBubbledEvent@http://localhost:3000/static/js/1.chunk.js:12015:36\nsetInitialProperties@http://localhost:3000/static/js/1.chunk.js:13826:27\nfinalizeInitialChildren@http://localhost:3000/static/js/1.chunk.js:15351:27\ncompleteWork@http://localhost:3000/static/js/1.chunk.js:26705:44\ncompleteUnitOfWork@http://localhost:3000/static/js/1.chunk.js:29895:20\nperformUnitOfWork@http://localhost:3000/static/js/1.chunk.js:29868:16\nworkLoopSync@http://localhost:3000/static/js/1.chunk.js:29833:26\nperformSyncWorkOnRoot@http://localhost:3000/static/js/1.chunk.js:29451:13\nscheduleUpdateOnFiber@http://localhost:3000/static/js/1.chunk.js:28883:32\nupdateContainer@http://localhost:3000/static/js/1.chunk.js:32032:19\nlegacyRenderSubtreeIntoContainer/<@http://localhost:3000/static/js/1.chunk.js:32415:26\nunbatchedUpdates@http://localhost:3000/static/js/1.chunk.js:29601:16\nlegacyRenderSubtreeIntoContainer@http://localhost:3000/static/js/1.chunk.js:32414:25\nrender@http://localhost:3000/static/js/1.chunk.js:32497:14\n./src/index.js@http://localhost:3000/static/js/main.chunk.js:4166:50\n__webpack_require__@http://localhost:3000/static/js/bundle.js:785:30\nfn@http://localhost:3000/static/js/bundle.js:151:20\n1@http://localhost:3000/static/js/main.chunk.js:4181:18\n__webpack_require__@http://localhost:3000/static/js/bundle.js:785:30\ncheckDeferredModules@http://localhost:3000/static/js/bundle.js:46:23\nwebpackJsonpCallback@http://localhost:3000/static/js/bundle.js:33:19\n@http://localhost:3000/static/js/main.chunk.js:1:71\n',
    config: {
      url: 'http://127.0.0.1:8000/rest-auth/register/',
      method: 'post',
      data: '{"fname":"Abhiram","lname":"PS","username":"rooteeee","phone":"8589967868","email":"[email protected]","cemail":"[email protected]","password1":"abhi1998","password2":"abhi1998","gender":"M","acctype":"Student"}',
      headers: {
        Accept: 'application/json, text/plain, */*',
        'Content-Type': 'application/json;charset=utf-8'
      },
      transformRequest: [
        null
      ],
      transformResponse: [
        null
      ],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1
    }
  }

以下是serializer.py的源代码。

from rest_framework import serializers
from accounts.models import Account
from allauth.account import app_settings as allauth_settings
from allauth.utils import email_address_exists
from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email
from rest_framework.validators import UniqueValidator
from rest_framework.response import Response
from rest_framework import status


class CustomUserDetailsSerializer(serializers.ModelSerializer):

        class Meta:
            model = Account
            fields = ('pk','email','fname','lname','username','phone','gender','acctype')
            #read_only_fields = ('email','acctype','fname','lname')




class CustomRegisterSerializer(serializers.Serializer):
    fname = serializers.CharField(required=True, write_only=True)
    lname = serializers.CharField(required=True, write_only=True)
    username = serializers.CharField(min_length=allauth_settings.USERNAME_MIN_LENGTH,required=allauth_settings.USERNAME_REQUIRED,validators=[UniqueValidator(queryset=Account.objects.all(),message='A user is already registered with this Username.')])
    phone=serializers.CharField(required=True, write_only=True,min_length=10,max_length=10)
    email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
    cemail = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
    password1 = serializers.CharField(write_only=True, required=True)
    password2 = serializers.CharField(write_only=True, required=True)

    acctype=serializers.ChoiceField(['Student','Staff'])
    gender=serializers.ChoiceField([('M','M'),('F','F')])
    def validate_email(self, email):
        email = get_adapter().clean_email(email)
        if allauth_settings.UNIQUE_EMAIL:
            if email and email_address_exists(email):
                raise serializers.ValidationError(("A user is already registered with this e-mail address."))
        return email
    def validate_password1(self, password):
        return get_adapter().clean_password(password)
    def validate(self, data):
        if data['password1'] != data['password2']:
            raise serializers.ValidationError(("The password fields didn't match."))
        if data['email'] !=data['cemail']:
            raise serializers.ValidationError(("The email fields didn't match."))
        return data
    def get_cleaned_data(self):
        return {
            'fname': self.validated_data.get('fname', ''),
            'lname': self.validated_data.get('lname', ''),
            'username': self.validated_data.get('username', ''),
            'acctype': self.validated_data.get('acctype', ''),
            'gender': self.validated_data.get('gender', ''),
            'phone': self.validated_data.get('phone', ''),
            'password1': self.validated_data.get('password1', ''),
            'email': self.validated_data.get('email', ''),
        }
    def save(self, request):
        adapter = get_adapter()
        user = adapter.new_user(request)
        self.cleaned_data = self.get_cleaned_data()
        adapter.save_user(request, user, self)
        setup_user_email(request, user, [])
        user.fname=self.cleaned_data.get('fname')
        user.lname=self.cleaned_data.get('lname')
        user.phone=self.cleaned_data.get('phone')
        user.acctype=self.cleaned_data.get('acctype')
        user.gender=self.cleaned_data.get('gender')
        user.save()
        return user

redux action creators文件(auth.js)如下所示。

import  * as actionTypes from './actionTypes'
import axios from 'axios'

export const authStart=()=>{
    return{
        type:actionTypes.AUTH_START
    }
}

export const authSuccess=(token)=>{
    return{
        type:actionTypes.AUTH_SUCCESS,
        token:token
    }
}

export const authFail=(error)=>{
    return{
        type:actionTypes.AUTH_FAIL,
        error:error
    }
}


export const checkAuthTimeout = expirationTime =>{
    return disaptch=>{
        setTimeout(()=>{
            disaptch(logout())
        },expirationTime * 1000)
    }
}

export const autLlogout=()=>{
    return{
        type:actionTypes.AUTH_LOGOUT
    }
}


export const authLogin=(username,password)=>{
    return disaptch=>{
        disaptch(authStart())
        axios.post('http://127.0.0.1:8000/rest-auth/login/',{
            username:username,
            password:password
        }).then(res=>{
            const token=res.data.key
            const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
            localStorage.setItem('token',token)
            localStorage.setItem('expirationDate',expirationDate)
            disaptch(authSuccess(token))
            disaptch(checkAuthTimeout(3600))
        }).catch(err=>{
            disaptch (authFail(err))
        })
    }
}
export const signUp=(fname,lname,username,phone,email,cemail,password1,password2,gender,acctype)=>{
    return disaptch=>{
        disaptch(authStart())
        axios.post('http://127.0.0.1:8000/rest-auth/register/',{
            fname:fname,
            lname:lname,
            username:username,
            phone:phone,
            email:email,
            cemail:cemail,
            password1:password1,
            password2:password2,
            gender:gender,
            acctype:acctype,
        }).then(res=>{
            const token=res.data.key
            const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
            localStorage.setItem('token',token)
            localStorage.setItem('expirationDate',expirationDate)
            disaptch(authSuccess(token))
            disaptch(checkAuthTimeout(3600))
        }).catch(err=>{
            disaptch (authFail(err))
        })
    }
} 
export const logout=()=>{
    localStorage.removeItem('uesr')
    localStorage.removeItem('expirationDate') 
    return {
        type:actionTypes.AUTH_LOGOUT
    }
}

export const authCheckState=()=>{
    return disaptch=>{
        const token=localStorage.getItem('token')
        if(token===undefined){
            disaptch(logout())
        }else{
            const expirationDate=new Date(localStorage.getItem('expirationDate'))
            if(expirationDate<=new Date()){
                disaptch(logout())
            }else{
                disaptch(authSuccess(token))
                disaptch(checkAuthTimeout((expirationDate.getTime()-new Date().getTime())/1000))
            }
        }
    }
}
django reactjs django-rest-framework react-redux django-serializer
1个回答
1
投票

乍一看,这个问题看起来是在react层。

Axios会把400状态码响应当作一个错误,而不是解析承诺和确定响应数据,而是会抛出你所看到的上面的错误。

处理这个问题的一个方法。

  axios.create({
    // ...vars
    responseType: "json",
    validateStatus: status => {
      // handling our own errors less than 500 status
      return status < 500;
    },
    headers: headers
  });

在创建初始的axios客户端时, 这将导致axios不抛出错误。

然后,在你的承诺中 .then(res=>{...}) 你需要检查400的响应状态码,并进行相应的错误处理。

代码。

export const authLogin=(username,password)=>{
    return dispatch=>{
        dispatch(authStart())
        axios.post('http://127.0.0.1:8000/rest-auth/login/',{
            username:username,
            password:password
        }, {
            validateStatus: status => {return status < 500}
        }).then(res=>{
            if (res.status === 400) {
                // Will have validation errors on response body
                dispatch(authFail(res.data))
            } else {
                const token=res.data.key
                const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
                localStorage.setItem('token',token)
                localStorage.setItem('expirationDate',expirationDate)
                dispatch(authSuccess(token))
                dispatch(checkAuthTimeout(3600))
            }
        }).catch(err=>{
            dispatch (authFail(err))
        })
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.