Django 및 React를 사용한 Python 채팅 자습서
다른 튜토리얼과 달리 저는 WebSocket 연결에 Python/Django를 사용하지 않습니다. 그렇게 하는 것이 기술적인 관점에서 멋있어 보일 수 있지만, 특히 사용자 수가 절반 정도인 경우에는 매우 느리고 비용이 많이 듭니다. C++, Go 및 Elixir와 같은 언어는 채팅의 핵심을 처리하는 데 훨씬 뛰어납니다.
이 자습서에서는 Go, Raft 및 RocksDB를 사용하여 WebSocket 연결 및 기타 무거운 작업을 처리하는 Stream을 사용합니다.
목차:
The GitHub repo for the code below can be found at https://github.com/GetStream/python-chat-example.
코딩하자! 🤓
1단계 – 반응 채팅 데모 UI
Before we start thinking about the Python chat side of things let's spin up a simple React frontend, so we have something nice and visual to look at:
$ yarn global add create-react-app
$ brew install node && brew install yarn # skip if installed
$ create-react-app chat-frontend
$ cd chat-frontend
$ yarn add stream-chat-react
Replace the code in src/App.js
with:
import React from "react";
import {
Chat,
Channel,
ChannelHeader,
Thread,
Window
} from "stream-chat-react";
import { MessageList, MessageInput } from "stream-chat-react";
import { StreamChat } from "stream-chat";
import "stream-chat-react/dist/css/index.css";
const chatClient = new StreamChat("qk4nn7rpcn75"); // Demo Stream Key
const userToken =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1za3ktOSJ9.mhikC6HPqPKoCP4aHHfuH9dFgPQ2Fth5QoRAfolJjC4"; // Demo Stream Token
chatClient.setUser(
{
id: "cool-sky-9",
name: "Cool sky",
image: "https://getstream.io/random_svg/?id=cool-sky-9&name=Cool+sky"
},
userToken
);
const channel = chatClient.channel("messaging", "godevs", {
// image and name are required, however, you can add custom fields
image:
"https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png",
name: "Talk about Go"
});
const App = () => (
<Chat client={chatClient} theme={"messaging light"}>
<Channel channel={channel}>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</Chat>
);
export default App;
Next, run yarn start
to see the chat in action!
2단계 - Django/Python 설정(이미 있는 경우 건너뛰기)
Make sure you have Python 3.7 up and running.
$ brew install python3
$ pip install virtualenv virtualenvwrapper
$ export WORKON_HOME=~/Envs
$ source /usr/local/bin/virtualenvwrapper.sh
$ mkvirtualenv chatexample -p `which python3`
$ workon chatexample
If that does not work, please try this snippet:
$ python3 -m venv chatexample
$ source chatexample/bin/activate
Now that you’re in your virtual env you should see python 3 when you run:
$ python --version
To kick off a new Django project, use the following snippet:
$ pip install django
$ django-admin startproject mychat
And to start your app:
$ cd mychat
$ python manage.py runserver
Now, when you open http://localhost:8000
, you should see this:
3단계 - 사용자 인증
As a next step lets setup Django’s user auth.
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
Visit http://localhost:8000/admin/
and login. Voila!
You should see the Django admin screen as shown below:
4단계 - Django Rest 프레임워크
One of my favorite packages for integrating react with Django is Django Rest Framework. To make everything work, we will need to create endpoints for:
- User Signup
- User Login
Djoser를 설치하려면 다음 스니펫을 사용하십시오.
$ pip install djangorestframework djoser
그런 다음 편집
urls.py
하고 다음을 포함하도록 파일을 변경합니다.from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.authtoken')),
]
완료되면
settings.py
편집하고 다음과 같이 변경합니다.INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'djoser',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
Djoser가 노출하는 API 엔드포인트에 대한 자세한 내용은 다음을 참조하세요.
https://djoser.readthedocs.io/en/latest/sample_usage.html
이제 등록 끝점을 테스트해 보겠습니다.
$ curl -X POST http://127.0.0.1:8000/auth/users/ --data 'username=djoser&password=alpine12'
5단계 - Stream의 채팅 서버에 액세스하기 위한 토큰 생성
Now we need to customize the Djoser views to generate tokens for Stream. Let’s get started.
Let's organize our files a bit and create a chat app folder in our project (make sure that you are in the correct directory):
$ python manage.py startapp auth
Install stream-chat:
$ pip install stream-chat
Create a custom serializer in auth/serializers.py
with the following logic:
from djoser.serializers import TokenSerializer
from rest_framework import serializers
from djoser.conf import settings as djoser_settings
from stream_chat import StreamChat
from django.conf import settings
class StreamTokenSerializer(TokenSerializer):
stream_token = serializers.SerializerMethodField()
class Meta:
model = djoser_settings.TOKEN_MODEL
fields = ('auth_token','stream_token')
def get_stream_token(self, obj):
client = StreamChat(api_key=settings.STREAM_API_KEY, api_secret=settings.STREAM_API_SECRET)
token = client.create_token(obj.user.id)
return token
And last, use the custom serializer by updating your settings.py
file:
STREAM_API_KEY = YOUR_STREAM_API_KEY # https://getstream.io/dashboard/
STREAM_API_SECRET = YOUR_STREAM_API_SECRET
DJOSER = {
'SERIALIZERS': {
'token': 'auth.serializers.StreamTokenSerializer',
}
}
Rerun your migration:
$ python manage.py migrate
To verify that it works, hit the login endpoint with a POST request:
$ curl -X POST http://127.0.0.1:8000/auth/token/login/ --data 'username=djoser&password=alpine12'
Both the auth_token
and stream_token
should be returned.
6단계 - React에 인증 통합
Adding an auth later to the frontend is an essential step for obvious reasons. In our case, it’s especially useful because we can fetch a user token from the backend API (powered by Python) and dynamically use it when sending messages.
First, install the CORS middleware package for Django:
$ pip install django-cors-headers
Then, modify your settings.py
to reference the djors-cors-header
middleware:
INSTALLED_APPS = (
...
'corsheaders',
...
)
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
And finally, add the following to your settings.py
file:
CORS_ORIGIN_ALLOW_ALL = True
The next step requires a few modifications to be made to your frontend. To start, you will want to ensure that you have all of the dependencies installed via yarn:
$ yarn add axios react-dom react-router-dom
Next, create the following files within your src/
directory:
- AuthedRoute.js
- UnauthedRoute.js
- withSession.js
- Login.js
- Chat.js
App.js
import React from "react";
import { BrowserRouter as Router, Switch } from "react-router-dom";
import Chat from "./Chat";
import Login from "./Login";
import UnauthedRoute from "./UnauthedRoute";
import AuthedRoute from "./AuthedRoute";
const App = () => (
<Router>
<Switch>
<UnauthedRoute path="/auth/login" component={Login} />
<AuthedRoute path="/" component={Chat} />
</Switch>
</Router>
);
export default App;
AuthedRoute.js
import React from "react";
import { Redirect, Route } from "react-router-dom";
const AuthedRoute = ({ component: Component, loading, ...rest }) => {
const isAuthed = Boolean(localStorage.getItem("token"));
return (
<Route
{...rest}
render={props =>
loading ? (
<p>Loading...</p>
) : isAuthed ? (
<Component history={props.history} {...rest} />
) : (
<Redirect
to={{
pathname: "/auth/login",
state: { next: props.location }
}}
/>
)
}
/>
);
};
export default AuthedRoute;
UnauthedRoute.js
import React from "react";
import { Redirect, Route } from "react-router-dom";
const AuthedRoute = ({ component: Component, loading, ...rest }) => {
const isAuthed = Boolean(localStorage.getItem("token"));
return (
<Route
{...rest}
render={props =>
loading ? (
<p>Loading...</p>
) : !isAuthed ? (
<Component history={props.history} {...rest} />
) : (
<Redirect
to={{
pathname: "/"
}}
/>
)
}
/>
);
};
export default AuthedRoute;
withSession.js
import React from "react";
import { withRouter } from "react-router";
export default (Component, unAuthed = false) => {
const WithSession = ({ user = {}, streamToken, ...props }) =>
user.id || unAuthed ? (
<Component
userId={user.id}
user={user}
session={window.streamSession}
{...props}
/>
) : (
<Component {...props} />
);
return withRouter(WithSession);
};
Login.js
import React, { Component } from "react";
import axios from "axios";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
email: "",
password: ""
};
this.initStream = this.initStream.bind(this);
}
async initStream() {
await this.setState({
loading: true
});
const base = "http://localhost:8000";
const formData = new FormData();
formData.set("username", this.state.email);
formData.set("password", this.state.password);
const registration = await axios({
method: "POST",
url: `${base}/auth/users/`,
data: formData,
config: {
headers: { "Content-Type": "multipart/form-data" }
}
});
const authorization = await axios({
method: "POST",
url: `${base}/auth/token/login/`,
data: formData,
config: {
headers: { "Content-Type": "multipart/form-data" }
}
});
localStorage.setItem("token", authorization.data.stream_token);
await this.setState({
loading: false
});
this.props.history.push("/");
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
render() {
return (
<div className="login-root">
<div className="login-card">
<h4>Login</h4>
<input
type="text"
placeholder="Email"
name="email"
onChange={e => this.handleChange(e)}
/>
<input
type="password"
placeholder="Password"
name="password"
onChange={e => this.handleChange(e)}
/>
<button onClick={this.initStream}>Submit</button>
</div>
</div>
);
}
}
export default Login;
Chat.js
import React, { Component } from "react";
import {
Chat,
Channel,
ChannelHeader,
Thread,
Window
} from "stream-chat-react";
import { MessageList, MessageInput } from "stream-chat-react";
import { StreamChat } from "stream-chat";
import "stream-chat-react/dist/css/index.css";
class App extends Component {
constructor(props) {
super(props);
this.client = new StreamChat("<YOUR_STREAM_APP_ID>");
this.client.setUser(
{
id: "cool-sky-9",
name: "Cool Sky",
image: "https://getstream.io/random_svg/?id=cool-sky-9&name=Cool+sky"
},
localStorage.getItem("token")
);
this.channel = this.client.channel("messaging", "godevs", {
image:
"https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png",
name: "Talk about Go"
});
}
render() {
return (
<Chat client={this.client} theme={"messaging light"}>
<Channel channel={this.channel}>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</Chat>
);
}
}
export default App;
Be sure to replace YOUR_STREAM_APP_ID
with a valid Stream App ID which can be found on the .
Restart your frontend application and you should be hit with an auth wall! Enter your email and password and a token will be requested and stored in local storage.
7단계 - Python 채팅 서버에서 메시지 보내기
Occasionally, you will want to write to the chat API using your backend Python-based server. Here’s a quick management command that you can use:
Verify that installed apps looks like this in settings.py
:
INSTALLED_APPS = [
'corsheaders',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'djoser',
]
Next, create the directory chat/management/commands
. In that directory, add a file called broadcast.py
with this content:
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from stream_chat import StreamChat
class Command(BaseCommand):
help = 'Broadcast the message on your channel'
def add_arguments(self, parser):
parser.add_argument('--message')
def handle(self, *args, **options):
client = StreamChat(api_key=settings.STREAM_API_KEY, api_secret=settings.STREAM_API_SECRET)
client.update_user({"id": "system", "name": "The Server"})
channel = client.channel("messaging", "kung-fu")
channel.create("system")
response = channel.send_message({"text": "AMA about kung-fu"}, 'system')
self.stdout.write(self.style.SUCCESS('Successfully posted a message with id "%s"' % response['message']['id']))
You can try posting a message to the chat like this:
$ python manage.py broadcast --message hello
And you should see a response like this:
마지막 생각들
I hope you enjoyed this tutorial on building a chat application with Django, Python and React!
For an interactive tour of , please have a look at our on the Stream website. If you are interested in digging into the code for Stream Chat React Components, the full docs can be found here . Stream 위에 채팅을 구축하는 데 관심이 있는 경우 최신 버전SDKs과 함께 인기 있는 언어 및 프레임워크에 대한 다양한iOS (Swift)을 제공합니다.즐거운 코딩! ✌
Reference
이 문제에 관하여(Django 및 React를 사용한 Python 채팅 자습서), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nickparsons/tutorial-chat-with-python-django-and-react-1cpk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)