рд╢реБрдн рджреЛрдкрд╣рд░, рджреЛрд╕реНрддреЛрдВред
рдкрд╛рдпрдерди рд╡реЗрдм рдбреЗрд╡рд▓рдкрд░ рдкрд╛рдареНрдпрдХреНрд░рдо рдХреА рд╢реБрд░реБрдЖрдд рдХреА рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдореЗрдВ
, рд╣рдо рдкрд╛рд░рдВрдкрд░рд┐рдХ рд░реВрдк рд╕реЗ рдЖрдкрдХреЗ рд╕рд╛рде рдПрдХ рдЙрдкрдпреЛрдЧреА рдЕрдиреБрд╡рд╛рдж рд╕рд╛рдЭрд╛ рдХрд░рддреЗ рд╣реИрдВред

рдЖрдк рдЕрдкрдиреЗ рд╕рд╛рдордиреЗ рдПрдХ рдЧрд╛рдЗрдб рджреЗрдЦрддреЗ рд╣реИрдВ рдЬреЛ рдЖрдкрдХреЛ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдкрд╛рдпрдерди, Django рдФрд░ рд░рд┐рдПрдХреНрдЯ рдореЗрдВ рдПрдХ рдЪреИрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдПредрдЕрдиреНрдп рдореИрдиреБрдЕрд▓ рдХреЗ рд╡рд┐рдкрд░реАрдд, рдореИрдВ WebSocket рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдкрд╛рдпрдерди рдФрд░ Django рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВред рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдпрд╣ рддрдХрдиреАрдХреА рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ рдЕрдЪреНрдЫрд╛ рд▓рдЧрддрд╛ рд╣реИ, рдпрд╣ рд╕реБрд╕реНрдд рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдорд╣рдВрдЧрд╛ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдПрдХ рд╕рднреНрдп рд╕рдВрдЦреНрдпрд╛ рд╣реИред C ++, Go рдФрд░ Elixir рдЬреИрд╕реА рднрд╛рд╖рд╛рдПрдВ рдЪреИрдЯ рдХреЛрд░ рдХрд╛ рдмреЗрд╣рддрд░ рдХрд╛рдо рдХрд░рддреА рд╣реИрдВред
рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ, рд╣рдо рд╕реНрдЯреНрд░реАрдо, рдПрдХ
рдЪреИрдЯ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдЬреЛ рдХрд┐ рд╡реЗрдмрд╕реЙрдХреЗрдЯ рдХрдиреЗрдХреНрд╢рди рдФрд░ рдЕрдиреНрдп рднрд╛рд░реА рдкрд╣рд▓реБрдУрдВ рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдЧреЛ, рд░рдлрдЯ рдФрд░ рд░реЙрдХреНрд╕рдбреАрдмреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╕рд╛рдордЧреНрд░реА:
- рд░рд┐рдПрдХреНрдЯ рдбреЗрдореЛ рдЪреИрдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕
- Django / рдкрд╛рдпрдерди рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ
- рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рд╛рдзрд┐рдХрд░рдг
- Django рдмрд╛рдХреА рдврд╛рдВрдЪрд╛
- рдЪреИрдЯ рд╕реНрдЯреНрд░реАрдо рд╕рд░реНрд╡рд░ рддрдХ рдкрд╣реБрдВрдЪ рдХреЗ рд▓рд┐рдП рдЯреЛрдХрди рдкреАрдврд╝реА
- рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдПрдХреАрдХрд░рдг
- рдкрд╛рдпрдерди рд╕рд░реНрд╡рд░ рд╕реЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдирд╛
- рдЕрдВрддрд┐рдо рд╡рд┐рдЪрд╛рд░
рдПрдХ рд▓реЗрдЦ рд╕реЗ рдХреЛрдб рдХреЗ рд╕рд╛рде Github рднрдВрдбрд╛рд░
рдЪрд▓реЛ рд╢реБрд░реВ рд╣реЛ рдЬрд╛рдУ!
рдЪрд░рдг 1: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбреЗрдореЛ рдЪреИрдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдкрд╛рдпрдерди рднрд╛рдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ, рдЖрдЗрдП рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкрд░ рдПрдХ рд╕рд░рд▓ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рддреИрдирд╛рдд рдХрд░реЗрдВ рддрд╛рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рд╕реБрдВрджрд░ рдФрд░ рджреГрд╢реНрдп рд╣реЛ:
$ yarn global add create-react-app $ brew install node && brew install yarn
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЗ рд╕рд╛рде рдХреЛрдб рдХреЛ
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 рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ (рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЖрдкрдХреА рдЬрд░реВрд░рдд рдХреА рд╕рднреА рдЪреАрдЬреЗрдВ рд╣реИрдВ рддреЛ рдЗрд╕ рдЪрд░рдг рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ)
рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкрд╛рдпрдерди 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
рдЕрдм рдЬрдм рдЖрдк рдЕрдкрдиреЗ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдкрд░ рдЕрдЬрдЧрд░ 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 рдмрд╛рдХреА рдлреНрд░реЗрдорд╡рд░реНрдХ
Django рдХреЗ рд╕рд╛рде рд░рд┐рдПрдХреНрдЯ рдХреЛ рдПрдХреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░рд╛ рдкрд╕рдВрджреАрджрд╛ рдкреИрдХреЗрдЬ Django рд░реЗрд╕реНрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рд╣реИред рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
- рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкрдВрдЬреАрдХрд░рдг
- рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд▓реЙрдЧрд┐рдиред
рд╣рдо рдЙрдиреНрд╣реЗрдВ рдЦреБрдж рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдПрдХ рдкреИрдХреЗрдЬ рд╣реИ рдЬрд┐рд╕реЗ
Djoser рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкрдВрдЬреАрдХрд░рдг, рд▓реЙрдЧрд┐рди, рдкрд╛рд╕рд╡рд░реНрдб рд░реАрд╕реЗрдЯ рдЖрджрд┐ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдПрдкреАрдЖрдИ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдЧрд╛ред
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 рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдПрдкреАрдЖрдИ рдПрдВрдбрдкреЙрдЗрдВрдЯреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЗрдЦреЗрдВ:
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 рджреГрд╢реНрдпреЛрдВ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рддреЛ рдЪрд▓рд┐рдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
рдЖрдЗрдП рд╣рдорд╛рд░реА рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рдереЛрдбрд╝рд╛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВ рдФрд░ рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдЪреИрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ (рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдк рд╕рд╣реА рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рд╣реИрдВ):
$ python manage.py startapp auth
рд╕реНрдЯреНрд░реАрдо-рдЪреИрдЯ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:
$ pip install stream-chat
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдПрдХ рдХрд╕реНрдЯрдо рд╕реАрд░рд┐рдпрд▓ рдирд┐рд░реНрдорд╛рддрд╛ рдХреЛ
auth/serializers.py
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
рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдкреБрдирд░рд╛рд░рдВрдн рдХрд░реЗрдВ:
$ python manage.py migrate
рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, POST рдЕрдиреБрд░реЛрдз рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдкрд░ рдЬрд╛рдПрдВ:
$ curl -X POST http://127.0.0.1:8000/auth/token/login/ --data 'username=djoser&password=alpine12'
рд╡рд╛рдкрд╕реА рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП
рдЪрд░рдг 6: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЛ рдПрдХреАрдХреГрдд рдХрд░реЗрдВ
рд╕реНрдкрд╖реНрдЯ рдХрд╛рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рджреГрд╢реНрдпрдкрдЯрд▓ рдкрд░ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдЬреЛрдбрд╝рдирд╛ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрджрдо рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдПрдкреАрдЖрдИ (рдЬреЛ рдкрд╛рдпрдерди рдкрд░ рдЪрд▓рддрд╛ рд╣реИ) рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯреЛрдХрди рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕рдВрджреЗрд╢ рднреЗрдЬрддреЗ рд╕рдордп рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, CORS рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ, рдЬреЛрдЬрд┐рдпреЛ рдХреЗ рд▓рд┐рдП рдорд┐рдбрд┐рд▓рд╡реЗрдпрд░ рдкреИрдХреЗрдЬ:
$ pip install django-cors-headers
рдлрд┐рд░
djors-cors-header
рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
settings.py
рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░реЗрдВ:
INSTALLED_APPS = ( ... 'corsheaders', ... ) MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ... ]
рдЕрдВрдд рдореЗрдВ, рдЕрдкрдиреА
settings.py
рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛ рдЬреЛрдбрд╝ рджреЗрдВ:
CORS_ORIGIN_ALLOW_ALL = True
рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ рдЖрдкрдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдХреБрдЫ рдмрджрд▓рд╛рд╡реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдпрд╛рд░реНрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рд╣реИрдВ:
$ 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
рдХреЛ рдмрджрд▓рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВред
рд╕рд╛рдордиреЗ рдХреЗ рдЫреЛрд░ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░реЗрдВ рдФрд░ рдЖрдк рдкреНрд░рд╛рдзрд┐рдХрд░рдг рджреЗрдЦреЗрдВрдЧреЗ! рдЕрдкрдирд╛ рдИрдореЗрд▓ рдкрддрд╛ рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рджрд░реНрдЬ рдХрд░реЗрдВ, рдЯреЛрдХрди рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╕реНрдерд╛рдиреАрдп рднрдВрдбрд╛рд░рдг рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЪрд░рдг 7: рдкрд╛рдпрдерди рд╕рд░реНрд╡рд░ рд╕реЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдирд╛
рдпрджрд┐ рдЖрдк рдЕрдЪрд╛рдирдХ рдкрд╛рдпрдерди рдореЗрдВ рдЕрдкрдиреЗ рдмреИрдХрдПрдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЪреИрдЯ рдПрдкреАрдЖрдИ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХрдорд╛рдВрдб рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд┐рдП рдЧрдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди
settings.py
рдореЗрдВ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреЗ
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', ]
рдЗрд╕рдХреЗ рдмрд╛рдж, рдЪреИрдЯ / рдкреНрд░рдмрдВрдзрди / рдХрдорд╛рдВрдб рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдмрдирд╛рдПрдВред рдЗрд╕ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ,
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 рдореЗрдВ рдПрдХ рдЪреИрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдкрд░ рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХрд╛ рдЖрдирдВрдж рд▓рд┐рдпрд╛!
рд╕реНрдЯреНрд░реАрдо рдЪреИрдЯ рдХреЗ рдЗрдВрдЯрд░реЗрдХреНрдЯрд┐рд╡ рджреМрд░реЗ рдХреЗ рд▓рд┐рдП, рдХреГрдкрдпрд╛
рд╕реНрдЯреНрд░реАрдо рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рдПрдкреАрдЖрдИ рдмрдирд╛рдиреЗ рдкрд░ рд╣рдорд╛рд░реЗ рдЧрд╛рдЗрдб рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВред рдпрджрд┐ рдЖрдк рд╕реНрдЯреНрд░реАрдо рдЪреИрдЯ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдореЗрдВ рдЦреБрджрд╛рдИ рдХрд╛ рдЖрдирдВрдж рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк
рдпрд╣рд╛рдВ рдкреВрд░реНрдг рдкреНрд░рд▓реЗрдЦрди рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк рд╕реНрдЯреНрд░реАрдо рдкрд░ рдПрдХ рдЪреИрдЯ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд▓реЛрдХрдкреНрд░рд┐рдп
рдПрд╕рдбреАрдХреЗ рдФрд░ рдирд╡реАрдирддрдо
рдЖрдИрдУрдПрд╕ (рд╕реНрд╡рд┐рдлреНрдЯ) рддрдХ рдХреА рд╡рд┐рднрд┐рдиреНрди
рдПрд╕рдбреАрдХреЗ рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рдХреЗ рдкреНрд░рд╕рдиреНрди рд╣реИрдВред
рд╡рд╣ рд╕рдм рд╣реИред рдЖрдкрдХреЛ
Django ORM рдЯреНрд░рд┐рдХреНрд╕ рдкрд░ рдЦреБрд▓реЗ рд╡реЗрдмрд┐рдирд╛рд░ рдореЗрдВ рдорд┐рд▓рддреЗ рд╣реИрдВ ред