Django+channels+websocket completes a real-time push system
foreword
Due to the company's project needs, it is necessary to build a display website and connect two cameras. When the photos of the cameras are transmitted, they will be displayed on the webpage in real time. Therefore, a small demo of the real-time push system is required, because the contact with django is not long ( About two weeks), it can be regarded as learning while doing. There are many real-time chat systems using channels on the Internet, and relatively few real-time push systems.
Ok, let's get to the point. The demo is developed with pycharm+django, and the specific libraries used are: channels, channels_redis. About the steps of project establishment, you can use Baidu yourself, so I won’t go into too much detail. When pycharm established the django project, it has already established a virtual environment for you. You basically don’t need to do many things, just code directly! ! !
(project name for example below (project:mysite, app:myapp)
project configuration
1. First add the relevant library
toolbar File–>Settings–>Project:(mysite)–>Project Interpreter–>±->channels+channel-redis
Special attention, channels-redis version 2.4.2, choose 3.0.1 will Conflict with the local redis server, the reason is unknown.
2. Modify the project settings and
add the app and channels you created together.
Because we use channels_redis, we will modify it together
ASGI_APPLICATION = 'mysite.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
3. Modify the routing
(you can also skip this step, just to make the project routing classification clearer and easier for later maintenance)
Add app routing Create a urls.py file /myapp/urls.py
in the myapp directory
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
Then import your app route /mysite/urls.py under the project route
from django.conf.urls import include
from django.urls import path
urlpatterns = [
path('', include('myapp.urls')),
]
The above step is equivalent to
modifying directly in /mysite/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
4. Add asgi application routing
We have modified ASGI_APPLICATION = 'mysite.routing.application' in settings,
so create a new routing.py in /mysite/
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import myapp.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
myapp.routing.websocket_urlpatterns
)
),
})
Here's a brief explanation: it lets you dispatch to one of many other ASGI applications based on the value present in the type scope. A protocol will define a fixed type of value that its scope contains, so you can use this to distinguish incoming connection types.
In short, point to different urls according to your needs (your view function is connected)
Then add the routing of the application
ie /myapp/routing.py
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('image/', consumers.PushConsumer),
]
5. Create a background push function Create consumers.py /myapp/consumers.py
in the myapp directory
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
# 推送consumer
class PushConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.group_name = 'image'
await self.channel_layer.group_add(
self.group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.group_name,
self.channel_name
)
# print(PushConsumer.chats)
async def push_message(self, event):
await self.send(text_data=json.dumps({
"message": event['message']
}))
# 构建函数,便于外部调用
def push(username, message):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
username,
{
"type": "push.message",
"message": message
}
)
6. Don't forget our view function view.py
from django.shortcuts import render
from .consumers import push
# Create your views here.
def index(request):
for i in range(10):
push('image',i)
return render(request, 'index.html')
Here is an example of a simple call
for i in range(10): push
('image',i)
pushes 0, 1, 2, 3...9 to all members of the image group
7. Establish our websocket connection on the webpage
and create an index.html page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>接收端</title>
</head>
<body>
<textarea id="log" cols="100" rows="20"></textarea><br>
<script>
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+'/image/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#log').value += (data.message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
</script>
</body>
</html>
This establishes the websocket connection
test
Open the local redis server, how to open it, please download it from Baidu and open it for testing. It
is the following stuff. The
official website download is too slow, so slow that it makes you suffocate. Don't wait stupidly, please find domestic resources by yourself.
If it is a local test, open several web pages locally, the default is 127.0.0.1:8000. The basic effect is that no webpage is opened, and the last webpage is to print the numbers from 0-9.
If the LAN method is used,
modify it in the settings.py file
ALLOWED_HOSTS = [你本地电脑的IP地址]
In this way, another computer in the same LAN can open the webpage for testing, and the effect is the same as that of local testing.
The above is a rookie, welcome to correct me, haha~
If you don’t understand, you can check the official documents: channels official documents
related documents