使用 Django 和 React 的 Python 聊天教程
本教程将解释如何使用 Python、Django 和 React 构建聊天应用程序。
与其他教程不同,我没有使用 Python/Django 进行 WebSocket 连接。虽然从技术角度来看这样做很酷,但它相当缓慢且昂贵——尤其是在用户数量尚可的情况下。C++、Go 和 Elixir 等语言在处理聊天核心方面要好得多。
在本教程中,我们将使用 Stream,这是一个用于聊天的 API,它使用 Go、Raft 和 RocksDB 来处理 WebSocket 连接和其他繁重的工作。
目录:
- React Chat 演示 UI
- Django/Python 设置
- 用户授权
- Django Rest框架
- 生成令牌以访问 Stream 的聊天服务器
- 在 React 中集成 Auth
- 从 Python 服务器发送消息
- 最后的想法
以下代码的 GitHub 仓库可以在https://github.com/GetStream/python-chat-example找到。
开始写代码吧!🤓
步骤 1 – React Chat 演示 UI
在我们开始考虑 Python 聊天方面的事情之前,让我们先启动一个简单的 React 前端,这样我们就可以看到一些漂亮且直观的东西:
$ 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
将代码替换src/App.js
为:
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;
接下来,运行yarn start
看看聊天的实际效果!
第 2 步 - Django/Python 设置(如果已经设置,请跳过)
确保 Python 3.7 已启动并运行。
$ brew install python3
$ pip install virtualenv virtualenvwrapper
$ export WORKON_HOME=~/Envs
$ source /usr/local/bin/virtualenvwrapper.sh
$ mkvirtualenv chatexample -p `which python3`
$ workon chatexample
如果这不起作用,请尝试这个代码片段:
$ python3 -m venv chatexample
$ source chatexample/bin/activate
现在您已处于虚拟环境中,运行时您应该会看到 python 3:
$ python --version
要启动一个新的 Django 项目,请使用以下代码片段:
$ pip install django
$ django-admin startproject mychat
并启动您的应用程序:
$ cd mychat
$ python manage.py runserver
现在,当您打开时http://localhost:8000
,您应该会看到以下内容:
步骤 3 - 用户身份验证
下一步让我们设置 Django 的用户身份验证。
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
访问http://localhost:8000/admin/
并登录。瞧!
您应该会看到如下所示的 Django 管理屏幕:
第 4 步 - Django Rest 框架
我最喜欢的用于将 React 与 Django 集成的软件包之一是 Django Rest Framework。为了使一切正常工作,我们需要创建以下端点:
- 用户注册
- 用户登录
我们可以自己构建这些;但是,有一个名为Djoser的包已经解决了这个问题。它配置了用户注册、登录、密码重置等所需的 API 端点。
要安装 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 的聊天服务器
现在我们需要自定义 Djoser 视图来为 Stream 生成 token。让我们开始吧。
让我们稍微组织一下文件,并在我们的项目中创建一个聊天应用程序文件夹(确保您在正确的目录中):
$ python manage.py startapp auth
安装流聊天:
$ pip install stream-chat
auth/serializers.py
使用以下逻辑创建自定义序列化器:
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
最后,通过更新settings.py
文件来使用自定义序列化器:
STREAM_API_KEY = YOUR_STREAM_API_KEY # https://getstream.io/dashboard/
STREAM_API_SECRET = YOUR_STREAM_API_SECRET
DJOSER = {
'SERIALIZERS': {
'token': 'auth.serializers.StreamTokenSerializer',
}
}
重新运行迁移:
$ python manage.py migrate
为了验证它是否有效,请使用 POST 请求访问登录端点:
$ curl -X POST http://127.0.0.1:8000/auth/token/login/ --data 'username=djoser&password=alpine12'
和auth_token
都应stream_token
归还。
步骤 6 - 在 React 中集成 Auth
出于显而易见的原因,稍后在前端添加身份验证至关重要。在我们的例子中,它特别有用,因为我们可以从后端 API(由 Python 提供支持)获取用户令牌,并在发送消息时动态使用它。
首先,为 Django 安装 CORS 中间件包:
$ pip install django-cors-headers
然后,修改您的settings.py
以引用djors-cors-header
中间件:
INSTALLED_APPS = (
...
'corsheaders',
...
)
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
最后,将以下内容添加到您的settings.py
文件中:
CORS_ORIGIN_ALLOW_ALL = True
下一步需要对你的前端进行一些修改。首先,你需要确保已经通过 yarn 安装了所有依赖项:
$ yarn add axios react-dom react-router-dom
接下来,在目录中创建以下文件src/
:
- AuthedRoute.js
- UnauthedRoute.js
- withSession.js
- 登录.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);
};
登录.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;
请确保将其替换为可在仪表板上YOUR_STREAM_APP_ID
找到的有效 Stream App ID 。
重启你的前端应用程序,你应该会遇到身份验证墙!输入你的邮箱和密码,系统会请求一个令牌并将其存储在本地存储中。
步骤 7 - 从 Python 聊天服务器发送消息
有时,您需要使用基于 Python 的后端服务器写入聊天 API。您可以使用以下快速管理命令:
验证已安装的应用程序是否如下所示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',
]
接下来,创建目录chat/management/commands
。在该目录中,添加一个名为的文件,broadcast.py
内容如下:
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']))
您可以尝试像这样向聊天发送消息:
$ python manage.py broadcast --message hello
您应该会看到如下响应:
最后的想法
我希望您喜欢本教程,使用 Django、Python 和 React 构建聊天应用程序!
如需体验Stream Chat的交互式体验,请参阅Stream 网站上的API 教程。如果您有兴趣深入了解 Stream Chat React Components 的代码,完整文档可在此处找到。如果您有兴趣在 Stream 上构建聊天功能,我们为各种热门语言和框架提供了SDK,其中最新的是iOS (Swift)。
祝你编码愉快!✌
文章来源:https://dev.to/nickparsons/tutorial-chat-with-python-django-and-react-1cpk