Добрый день, друзья. В преддверии старта курса «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.