こんにちは、ジョンです。
フロントをReact、サーバーサイドをDjangoで開発する場合のログイン機能実装方法を記します。
以下、バージョン関係の情報です。
Django:4.2.8
React:^18.2.0",
OS:mac OS
開発環境の構築
まずはDjangoの環境を構築します。
プロジェクト名とアプリ名は任意の名前でOKです。
私はcoreとwebsiteという名前にしました。
python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install django
pip install djangorestframework
pip install django-cors-headers
pip freeze > requirements.txt
django-admin startproject core .
python manage.py startapp website
djangorestframeworkはリアクトとDjangoがAPIでの通信をするのに必要です。
django-cors-headersは、Reactからのリクエストがブロックされる
可能性を防ぐために、CORSヘッダーを設定するのに必要です。
Djangoの設定ファイル編集
INSTALLED_APPS = [
# --------------------
'website',# ←追加
'rest_framework',# ←追加
'corsheaders',# ←追加
]
MIDDLEWARE = [
# --------------------
'corsheaders.middleware.CorsMiddleware', # ←追加
]
# 以下追加
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000', # ReactアプリのURL
]
Reactのインストール
DjangoのルートディレクトリでReactをインストールします。
アプリ名は任意の名前でOKです。
npx create-react-app myapp
npm install react-router-dom # Reactでルーティング設定するのに必要
myapp ディレクトリ内のpackage.jsonにプロキシ設定を追加して、
APIリクエストをDjangoサーバーに転送できるようにする。
{
"name": "myapp",
----省略----
"browserslist": {
----省略----
},
"proxy": "http://localhost:8000"
}
ここまでの作業で問題ないかを確認するため、DjangoとReactでサーバーを立ち上げ、
エラーがないかを確認してください。
# Djangoのサーバー起動
# http://localhost:8000にアクセスできるか
python manage.py runserver
# Reactのサーバー起動
# http://localhost:3000にアクセスできるか
cd myapp
npm start
DjangoでAPIを受け取る処理を実装
Reactからのログインに関するリクエストを受け取った時の処理を記述します。
URLの設定
api/以降のリクエストはwebsiteのurlsを参照するように設定。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('api/', include('website.urls')),
path('admin/', admin.site.urls),
]
まだlogin_viewは作成していないので、以下のコードを保存するとエラーが
出るかもですが、最終的には以下のURLになります。
from django.urls import path
from .views.login_views import login_view
urlpatterns = [
path('login/', login_view, name='login'),
]
モデルの作成
今回はDjangoがデフォルトで用意しているUserモデルを使用するので
モデルの定義は省略します。(モデルを作成する必要ないです)
views作成
from django.contrib.auth import authenticate
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['POST'])
def login_view(request):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
# ユーザーが存在する場合の処理
return Response({'message': 'Login successful'})
else:
# ユーザーが存在しない場合の処理
return Response({'message': 'Invalid credentials'}, status=400)
- @api_view(['POST'])はDjango REST framework (DRF) におけるデコレーターの一つ
- POSTリクエストが行われた場合にのみ、関数が実行されます
- 他のHTTPメソッドでリクエストが行われた場合、Django REST frameworkは405 Method Not Allowedというレスポンスを返します
- usernameとpasswordにはログインフォームに入力された値が格納されます。
- POST リクエストのボディ内のデータのキー(フィールド名)と一致している必要があります。
- authenticateはDjangoがもともと要している関数で、Userモデルにリクエストされたusernameとpasswordが存在するかを探してくれます。
- Djangoが用意したUserモデルを使用しない場合は修正する必要があります
Reactでログインフォームを送信する機能を実装
LoginFormの作成
src/ディレクトリ内にcomponentsディレクトリを作成し、その中に
LoginForm.jsを作成します。
import React, { useState } from 'react';
import './LoginForm.css';
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
const response = await fetch('/api/login/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});
const data = await response.json();
if (response.status === 200) {
alert('Login successful');
} else {
alert(data.message);
}
};
return (
<div className="login-container">
<form className="login-form" onSubmit={handleSubmit}>
<input
type="text"
className="login-input"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Username"
/>
<input
type="password"
className="login-input"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit" className="login-button">Login</button>
</form>
</div>
);
}
export default LoginForm;
App.jsでルーティング設定
上記で作成したLoginFormをipmortして描画できるようにします。
import logo from './logo.svg';
import './App.css';
import React from 'react';
import LoginForm from './components/LoginForm';
function App() {
return (
<div>
<LoginForm />
</div>
);
}
export default App;
ReactでLoginForm.jsが描画されるまでのフロー解説
- http://localhost:3000/login にアクセスするとReactは public/index.html ファイルを読み込みます
- src/index.js ファイルはアプリケーションのエントリポイントで、ReactDOM.createRoot を使って Appコンポーネントを #root 要素にレンダリングします
- 次にApp コンポーネントが実行されます。このコンポーネント内で、ルーティングが設定されている場合、React Routerが特定のパス(この場合は /login)に基づいて対応するコンポーネント(LoginForm)をレンダリングします。
- LoginForm コンポーネントがレンダリングされ、ログインフォームがユーザーに表示されます。ユーザーはフォームに入力し、ログイン情報を送信できます
- LoginForm の handleSubmit 関数が、フォームの送信時に実行されます。この関数は、ユーザーの入力をDjangoサーバーの /api/login/ エンドポイントにPOSTリクエストとして送信し、応答に基づいて適切なアクションを行います
以上でReactとDjangoを使用したログイン機能を実装できました。
PS:LoginFormの見た目を良くするため、CSSを作成していたので、CSSも含めたい場合は
LoginForm.jsと同じディレクトリにLoginForm.cssを作成してください。
/* LoginForm.css */
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* ビューポートの高さに合わせる */
}
.login-form {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.login-input {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
width: 200px;
}
.login-button {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
width: 220px; /* インプットと同じ幅に */
}
.login-button:hover {
background-color: #0056b3;
}