Добрый день, друзья. В преддверии старта курса «Web-разработчик на Python» традиционно делимся с вами полезным переводом.

Вы видите перед собой руководство, которое расскажет, как создать приложение-чат на Python, Django и React.
В отличие от других руководств, я не использую Python и Django для WebSocket-соединений. Несмотря на то, что это звучит круто с технической точки зрения, работает это довольно вяло и само по себе затратно, особенно, если у вас приличное количество пользователей. Такие языки, как C++, Go и Elixir намного лучше справляются с ядром чата.
В этом руководстве мы будем использовать Stream, API для чата, которое позаботится о WebSocket- соединениях и других тяжелых аспектах, используя Go, Raft и RocksDB.
Содержание:
Начнем!
Прежде чем мы начнем думать о Python-части, давайте развернем простенький интерфейс на React, чтобы у нас было что-то красивое и визуальное:
Замените код в
А теперь, используйте команду
Убедитесь, что у вас есть Python 3.7 и он запущен:
Если не сработало, попробуйте следующий код:
Теперь, когда вы в своей виртуальной среде, вы должны увидеть python 3 при запуске:
Чтобы создать новый проект на Django, используйте следующий код:
И запустите приложение:
Теперь, когда вы откроете

Следующий шаг – настройка авторизации пользователей в Django.
Перейдите на
Вы увидите вкладку администратора на подобие той, что ниже:

Один из моих любимых пакетов для интеграции React с Django – это Django Rest Framework. Чтобы все заработало, нужно создать конечные точки для:
Мы могли бы сделать их самостоятельно, однако существует пакет под названием Djoser, который решает эту проблему. Он настроит необходимые конечные точки API для регистрации пользователей, входа в систему, сброса пароля и т.д.
Чтобы установить Djoser, используйте следующее:
После этого отредактируйте
По завершении, отредактируйте
Для получения дополнительной информации о конечных точках API, которые предоставляет Djoser, посмотрите следующее:
https://djoser.readthedocs.io/en/latest/sample_usage.html
Теперь давайте продолжим и протестируем конечную точку регистрации:
Теперь нам нужно настроить представления Djoser для генерации токенов Stream. Итак, начнем.
Давайте немного упорядочим наши файлы и создадим папку приложения чата в нашем проекте (убедитесь, что вы находитесь в правильном каталоге):
Установите stream-chat:
Создайте кастомный сериализатор в
И последнее, используйте кастомный сериализатор, чтобы обновить файл
Перезапустите миграцию:
Чтобы убедиться, что он работает, попадите в конечную точку с помощью POST-запроса:
Вернуться должны
По очевидным причинам, добавление авторизации к фронтенду – это важный шаг. В нашем случае это особенно полезно, поскольку мы можем извлечь токен пользователя из API (которое работает на Python) и динамически использовать его при отправке сообщений.
Во-первых, установите CORS – пакет промежуточного программного обеспечения для Django:
Затем измените файл
И наконец добавьте следующее к вашему файлу
Следующий шаг потребует внесения нескольких изменений в ваш интерфейс. Для начала вам нужно будет убедиться, что у вас есть все зависимости, установленные через yarn:
Далее создайте следующие файлы в директории
Обязательно замените
Перезапустите приложение на фронтенде и вы увидите авторизацию! Введите адрес электронной почты и пароль, токен будет запрошен и сохранен в локальном хранилище.
Если вы внезапно захотите создать API чата с использованием вашего бэкенда на Python, есть специальная команда, которую можно использовать.
Убедитесь, что установленные приложения выглядят следующим образом в
Далее создайте каталог chat/management/commands. В этот каталог добавьте файл с именем
Вы можете попробовать отправить сообщение в чат следующим образом:
И вы увидите такой отклик:

Надеюсь, вам понравилось это руководство по созданию приложения-чата на Django, Python и React!
Для интерактивного тура по Stream Chat, пожалуйста, взгляните на наше руководство по созданию API на сайте Stream. Если вам нравится копаться в коде компонентов Stream Chat React, полную документацию вы можете найти здесь. Если вам захочется создать ч��т на Stream, мы рады предложить различные SDK для популярных языков и фреймворков до последней iOS (Swift).
На этом все. До встречи на открытым вебинаре по теме Трюки Django ORM.

Вы видите перед собой руководство, которое расскажет, как создать приложение-чат на Python, Django и React.
В отличие от других руководств, я не использую Python и Django для WebSocket-соединений. Несмотря на то, что это звучит круто с технической точки зрения, работает это довольно вяло и само по себе затратно, особенно, если у вас приличное количество пользователей. Такие языки, как C++, Go и Elixir намного лучше справляются с ядром чата.
В этом руководстве мы будем использовать Stream, API для чата, которое позаботится о WebSocket- соединениях и других тяжелых аспектах, используя Go, Raft и RocksDB.
Содержание:
- Интерфейс демо-чата на React
- Установка Django/Python
- Авторизация пользователей
- Django Rest Framework
- Генерация токенов для доступа к Stream-серверу чата
- Интеграция авторизации в React
- Отправка сообщений с сервера Python
- Последние мысли
Github-репозиторий с кодом из статьи
Начнем!
Шаг 1: Интерфейс демо-чата на React
Прежде чем мы начнем думать о 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', ) }
Для получения дополнительной информации о конечных точках API, которые предоставляет Djoser, посмотрите следующее:
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. Итак, начнем.
Давайте немного упорядочим наши файлы и создадим папку приложения чата в нашем проекте (убедитесь, что вы находитесь в правильном каталоге):
$ python manage.py startapp auth
Установите stream-chat:
$ 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
По очевидным причинам, добавление авторизации к фронтенду – это важный шаг. В нашем случае это особенно полезно, поскольку мы можем извлечь токен пользователя из 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 на валидный ID приложения Stream, который можно найти на дашборде.Перезапустите приложение на фронтенде и вы увидите авторизацию! Введите адрес электронной почты и пароль, токен будет запрошен и сохранен в локальном хранилище.
Шаг 7: Отправка сообщений с сервера Python
Если вы внезапно захотите создать API чата с использованием вашего бэкенда на Python, есть специальная команда, которую можно использовать.
Убедитесь, что установленные приложения выглядят следующим образом в
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, пожалуйста, взгляните на наше руководство по созданию API на сайте Stream. Если вам нравится копаться в коде компонентов Stream Chat React, полную документацию вы можете найти здесь. Если вам захочется создать ч��т на Stream, мы рады предложить различные SDK для популярных языков и фреймворков до последней iOS (Swift).
На этом все. До встречи на открытым вебинаре по теме Трюки Django ORM.
