Tuesday, 4 June 2019

django 40 django + react + redux fetch token

username/password mismatch

redux logger shows rejected action

login success, token obtained

redux logger shows fulfilled action

#powershell
#django rest framework enable cors

pip install djangorestframework
pip install django-cors-headers

------------------------------------
#django settings

INSTALLED_APPS = (
    ...
    'rest_framework',
    'rest_framework.authtoken',
    'corsheaders',
)

MIDDLEWARE_CLASSES = (
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
                'rest_framework.authentication.TokenAuthentication',
                ),
    'DEFAULT_PERMISSION_CLASSES':(
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend',
    ),
}

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

-------------------------------------------
#django url

from django.urls import path
from rest_framework.authtoken import views

urlpatterns = [
    path('api-token-auth/', views.obtain_auth_token, name='AuthToken'),
]

-----------------------------------
//react directories

//index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.min.css';
import 'antd/dist/antd.css';
import { Provider } from "react-redux";
import store from "./redux/store";

ReactDOM.render(
    <Provider store={store}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </Provider>, document.getElementById('root'));

serviceWorker.unregister();

--------------------------------------------
//app.js

import React, { Component } from 'react';
import './App.css';
import Header from './partials/header';
import Body from './partials/body';

class App extends Component {
  render() {
    return (
      <div>
        <Header />
        <Body />
      </div>
    );
  }
}

export default App;

---------------------------------------------
//partials/body.js

import React, { Component } from 'react';
import '../App.css';
import { Switch, Route } from 'react-router-dom';
import Albums from '../pages/albums';
import Login from '../pages/login';


export default class Body extends Component {

    render() {
        return (
            <main className='Body-Background'>
                <Switch>
                    <Route exact path='/' component={Albums} />
                    <Route exact path='/login/' component={Login} />
                </Switch>
            </main>
        );
    }
}

-----------------------------------------------
//pages/login.js

import React, { Component } from 'react';
import '../App.css';
import { Input } from 'antd';
import { FaUser, FaBarcode } from "react-icons/fa";
import { Button } from 'reactstrap';
import axios from 'axios';
import { connect } from 'react-redux';
import { fetchToken } from '../redux/actions/loginAction'

class Login extends Component {
    constructor(props) {
        super(props);

        this.state = {
            username: '',
            password: '',
        };
    }

    inputChange = (e, p) => {
        this.setState({ [p]: e.target.value });
    }

    formSubmit = (e) => {
        e.preventDefault();

        this.props.dispatch(fetchToken(this.state.username, this.state.password))
    }

    render() {
        return (
            <form style={{ marginLeft: '10px', width: '300px' }}
                onSubmit={(e) => this.formSubmit(e)}>
                <legend>Login</legend>
                <hr />
                <p style={{ color: 'red' }}>{this.props.error}</p>
                <p style={{ color: 'blue' }}>Token: {this.props.token}</p>
                <Input placeholder="username" required='required'
                    prefix={<FaUser style={{ color: 'rgba(0,0,0,.25)' }} />}
                    onChange={(e) => this.inputChange(e, 'username')}
                    style={{ marginTop: '5px' }}
                />
                <Input placeholder="password" required='required' type='password'
                    prefix={<FaBarcode style={{ color: 'rgba(0,0,0,.25)' }} />}
                    onChange={(e) => this.inputChange(e, 'password')}
                    style={{ marginTop: '15px' }}
                />
                <Button color="success" type='submit' size='sm'
                    style={{ marginTop: '15px' }}
                >Submit</Button>
            </form>
        );
    }
}

export default connect(
    (store) => {
        return {
            username: store.login.username,
            token: store.login.token,
            loggingin: store.login.fetching,
            loggedin: store.login.fetched,
            error: store.login.error
        };
    }
)(Login);

---------------------------------------------
//redux/actions/loginAction

import axios from 'axios';

export function fetchToken(username, password) {
    return {
        type: "fetch_token",
        payload: axios({
            method: 'post',
            url: 'http://127.0.0.1:8000/api/api-token-auth/',
            data: {
                'username': username,
                "password": password
            },
        })
    }
}

--------------------------------------
//redux/reducers/index

import { combineReducers } from 'redux';
import login from "./loginReduder";

export default combineReducers(
    {
        login
    })

-----------------------------
//redux/reducers/loginReducer

export default function reducer(
    state = {
        username: '',
        token: '',
        fetching: false,
        fetched: false,
        error: ''
    },
    action
) {
    switch (action.type) {
        case "fetch_token_PENDING": {
            return { ...state, fetching: true, fetched: false }
        }

        case "fetch_token_FULFILLED": {
            return {
                ...state,
                fetching: false,
                fetched: true,
                token: action.payload.data.token,
                error: ''
            }
        }

        case "fetch_token_REJECTED": {
            return {
                ...state,
                fetching: false,
                fetched: false,
                error: action.payload.toString()
            }
        }

        default:
            break;
    }
    return state;
}

---------------------------------
//redux/store

import { applyMiddleware, createStore } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import promise from 'redux-promise-middleware';

import reducer from "./reducers";

const middleware = applyMiddleware(promise, thunk, logger);

export default createStore(reducer, middleware);

reference:
http://chuanshuoge2.blogspot.com/2019/05/django-40-django-react.html

No comments:

Post a Comment