用Python和Django编写聊天

朋友们,下午好。 预期Python Web Developer课程的开始,我们通常会与您分享有用的翻译。




您会看到前面的指南,该指南告诉您如何在Python,Django和React中创建聊天应用程序。

与其他手册不同,我不使用Python和Django进行WebSocket连接。 尽管从技术角度来看它听起来很酷,但它运行缓慢且本身很昂贵,尤其是在用户数量不错的情况下。 诸如C ++,Go和Elixir之类的语言在聊天核心方面做得更好。

在本教程中,我们将使用Stream,这是一个聊天API ,使用Go,Raft和RocksDB来处理WebSocket连接和其他重要方面。

内容:

  • React演示聊天界面
  • 安装Django / Python
  • 用户授权
  • Django Rest框架
  • 用于访问聊天流服务器的令牌生成
  • React授权集成
  • 从Python服务器发送消息
  • 最后的想法

Github存储库以及文章中的代码

让我们开始吧!

步骤1:React Demo Chat界面


在开始考虑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/并登录。 瞧!

您将看到类似于以下内容的管理员标签:



步骤4:Django Rest Framework


我最喜欢的将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:生成令牌以访问聊天流服务器


现在,我们需要配置Djoser视图以生成Stream令牌。 因此,让我们开始吧。
让我们稍微整理一下文件并在我们的项目中创建一个聊天应用程序文件夹(确保您在正确的目录中):

 $ python manage.py startapp auth 

安装即时通讯:

 $ pip install stream-chat 

使用以下逻辑在auth/serializers.py创建自定义序列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_tokenstream_token

步骤6:整合React授权


出于显而易见的原因,向前端添加授权是重要的一步。 在我们的案例中,这特别有用,因为我们可以从API(在Python上运行)中提取用户令牌,并在发送消息时动态使用它。

首先,安装CORS,这是Django的中间件软件包:

 $ 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
  • 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; 

请确保将YOUR_STREAM_APP_ID替换为有效的Stream应用ID,该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组件的代码,可以在此处找到完整的文档。 如果您想在Stream上创建聊天,我们很高兴为最新的iOS(Swift)提供各种流行语言和框架的SDK

仅此而已。 在公开的Django ORM Tricks网络研讨会上见。

Source: https://habr.com/ru/post/zh-CN475672/


All Articles