The content written is the same as Official Tutorial. Other than the official docs, there is no kind article that explains Django's Channels from 1 to 10 in an easy-to-understand manner, and I was wondering how to learn, so I will write it down for later runners.
It's also tough that there are only articles like "You are reading the official document, right?" If the official documentation is a prerequisite, I'll read that! Like
I also think that the article is old and doesn't work well.
The best way to study is to start with the tutorial in the official Channel documentation, but if you find this article, you don't have to.
The intended reader is someone like "Django is a little usable, but I can't get my hands on Channels."
Also, first of all, I'm not familiar with Django myself. I will introduce how to make a working Websocket application for the time being.
Channels adds Websocket communication to traditional Django. HTTP communication is left as it is, and consumer is called instead of views only when websocket communication comes.
Next, there is the concept of channel, group, and layer (written in English for consistency with the document). channel: Something like a client's mailbox. If you send a message to this, it will eventually reach the client. group: A group of channels. It's like a chat room. I think that channels is based on a mechanism that notifies the entire group when there is a change in the group. layer: A further superordinate concept of group. I'm not sure what it is for. Basically, one is enough.
We will implement these as prerequisite knowledge. You can understand it by nuance even if you don't remember it, and it doesn't matter if you don't understand it.
Let's install chanells
Next, create a project. If you change the project name, please read it.
django-admin startproject mysite
Then move into the project
python3 manage.py startapp chat
If you change the app name, please read this as well.
Well, I'm not magical so far. Think of it as something like making only the shape first.
Next, blow off the contents of the chat. Delete or create the file so that it looks like the following.
chat/ init.py consumers.py routing.py urls.py views.py
Creating a file is really okay if you create a new file as usual.
As a result, the whole project will look like this.
chat/ migrations init.py consumers.py routing.py urls.py views.py mysite/ init.py asgi.py settings.py urls.py wsgi.py db.sqlite3 manage.py
This completes only the shape.
If you don't have asgi.py, you may have the wrong version of django. Please prepare a version that can use Channels.
Next, we will play with each file.
mystite/settings.py
#### **`mysite/settings.py`**
```python
INSTALLED_APPS = [
'channels',#add to
'chat',#add to
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
#Added at the bottom
ASGI_APPLICATION = 'mysite.asgi.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"#When using in-memory
},
}
Add'channels' and'app name' in INSTALLED_APPS. Well this is a Django spec. I added it at the bottom for the sake of clarity of the changes. A layer is a group, and according to the official document, one app and one layer are normal. "default" is the name of the layer.
Currently I am using in-memory, but it seems that it only works within the same process. So you can solve it by using a cache server called Redis. I think Redis is like shared memory.
#Recommended It is better to use a cache server called redis,
CHANNEL_LAYERS = {
'default': {
'BACKEND':'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
In this case, the Redis server on port number 6379 is used as the cache server.
mysite/urls.py Do the following:
mysite/urls.py
from django.conf.urls import include
from django.urls import path
from django.contrib import admin
urlpatterns = [
path('chat/', include('chat.urls')),
path('admin/', admin.site.urls),
]
include means to use a file with a different URL.
chat/urls.py
chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<str:room_name>/', views.room, name='room'),
]
It's exactly like Django in this regard. If there is nothing in the url, the index of views.py is called, and if there is something, the room of view.py is called. At that time, I took it out as room_name and used it in views.py.
chat/routing.py
chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
Next is the contents of routing.py. routing.py writes about websocket connections. It was written that re_path is due to the limitation of URLRouter, but I'm not sure. Well, I should write it like this. as_asgi () is a way to call to use the consumer class that will be prepared later. If you prepare a comsumer class and call it this way, it seems that the rest will be done without permission. I will show you how to write the comsumer class later.
mysite/asgi.py
mysite/asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = ProtocolTypeRouter({
"http": get_asgi_application(),#http://Nara here
"websocket": AuthMiddlewareStack(#ws:// wss://Nara here
URLRouter(
chat.routing.websocket_urlpatterns#chat/routing.py
)
),
})
This determines whether it is an HTTP connection or Websocket communication and sorts it. If it is HTTP, it jumps to chat/urls and returns it by HTTP using views etc. If it is Websocket, it will jump to routing.py and process it.
chat/consumers.py This is the processing of websocket. For the time being, please copy it and read it while looking at the explanation below.
chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
#Performance improves by adding async
#From websocketConsumer to AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']#scope has connection information,
self.room_group_name = 'chat_%s' % self.room_name#I'm making a room str
# Join room group
await self.channel_layer.group_add(
#Group participation processing, well, I write it like this, about
#ChatComsumer is synchronous but channel_layer is asynchronous
self.room_group_name,
self.channel_name
)
await self.accept()#accept websocket,If not accepted, it will be rejected
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(#Exit processing
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(#Send a message to a group
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
Well, it's a little long.
Originally it is not async, but it seems that implementing it with async will eliminate thread calls and improve performance (?). Therefore, await and async are attached.
connect, disconnect and receive are functions to call as_asgi () in chat/routing.py. If you write it like this, it seems that the rest will be done without permission. It seems that connect is executed when url is entered to connect, disconnect is executed when closed, and receive is executed when send.
By setting a specific function for the send type, that function will be executed when someone sends, which will eventually send a message from the server to the client. This time, chat_message corresponds to that, and as a result, all clients belonging to the group are sent.
When moving it, please write HTML in chat/Templates/chat/referring to index.html in here and room.html in here.
py manage.py runserver
After running the server, access http://127.0.0.1:8000/chat/lobby/ with two browsers (windows).
Then what do you mean! It is also reflected on the other side! !! !! !!
Wow! !! !! !! !! !! !!
Yes.
Well, if you want to use it, please check with "JavaScript websocket", "python websocket", "Unity websocket". Maybe there is an event function like onReceive when sent from the server. that's all.
Official documentation tutorial https://channels.readthedocs.io/en/stable/tutorial/part_2.html
stack overflow「channels without channel layer or any other free hosting」 https://stackoverflow.com/questions/53271407/channels-without-channel-layer-or-any-other-free-hosting
Recommended Posts