Create your virtual environment.
download package in this order
Django==3.0.8
djangorestframework==3.11.0
websocket-client==0.57.0
redis==3.5.3
asgiref==3.2.10
channels-redis==2.4.2
channels==3.0.1
Then create a Django project named ChatApp.
django-admin startproject ChatApp
After installing channels, add channels to your installed apps.
INSTALLED_APPS = [
'chat.apps.ChatConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# add django channels
'channels' ,
]
Set the ASGI application to your default ASGI file in the project.
ASGI_APPLICATION = 'ChatApp.asgi.application'
Create a new app that will have all the chat functionality.
python manage.py startapp chat
And add your app to the installed apps in settings.py.
And add chat/urls.py
from django.urls import path, include
from chat import views as chat_views
urlpatterns = [
path("chat", chat_views.chatPage, name="chat-page"),
]
And add chat/routing.py
from django.urls import re_path
from chat.consumers import ChatConsumer
# Here, "ws" is routing to the URL ChatConsumer which
# will handle the chat functionality.
websocket_urlpatterns = [
re_path(r'ws$', ChatConsumer.as_asgi()),
]
And add chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.roomGroupName = "group_chat_gfg"
await self.channel_layer.group_add(
self.roomGroupName,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.roomGroupName,
self.channel_name
)
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
await self.channel_layer.group_send(
self.roomGroupName, {
"type": "sendMessage",
"message": message,
"username": username,
})
async def sendMessage(self, event):
message = event["message"]
username = event["username"]
await self.send(text_data=json.dumps({"message": message, "username": username}))
And add ChatApp/asgi.py
* Has anyone had problem like this?
Traceback (most recent call last):
File "/path/to/my/env/bin/daphne", line 11, in <module>
sys.exit(CommandLineInterface.entrypoint())
File "/path/to/my/env/lib/python3.6/site-packages/daphne/cli.py", line 161, in entrypoint
cls().run(sys.argv[1:])
File "/path/to/my/env/lib/python3.6/site-packages/daphne/cli.py", line 222, in run
application = import_by_path(args.application)
File "/path/to/my/env/lib/python3.6/site-packages/daphne/utils.py", line 12, in import_by_path
target = importlib.import_module(module_path)
File "/path/to/my/env/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./my_project/asgi.py", line 5, in <module>
application = get_default_application()
File "/path/to/my/env/lib/python3.6/site-packages/channels/routing.py", line 33, in get_default_application
module = importlib.import_module(path)
File "/path/to/my/env/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./my_project/routing.py", line 4, in <module>
from channels.auth import AuthMiddlewareStack
File "/path/to/my/env/lib/python3.6/site-packages/channels/auth.py", line 12, in <module>
from django.contrib.auth.models import AnonymousUser
File "/path/to/my/env/lib/python3.6/site-packages/django/contrib/auth/models.py", line 2, in <module>
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
File "/path/to/my/env/lib/python3.6/site-packages/django/contrib/auth/base_user.py", line 47, in <module>
class AbstractBaseUser(models.Model):
File "/path/to/my/env/lib/python3.6/site-packages/django/db/models/base.py", line 100, in __new__
app_config = apps.get_containing_app_config(module)
File "/path/to/my/env/lib/python3.6/site-packages/django/apps/registry.py", line 244, in get_containing_app_config
self.check_apps_ready()
File "/path/to/my/env/lib/python3.6/site-packages/django/apps/registry.py", line 127, in check_apps_ready
raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
Then visit this page.
ChatApp/settings.py
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
Using Redis:
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)]
},
},
}
* Deploying Django Channels: how to keep Daphne running after exiting shell on web server
Nginx
1. Windows
location @django {
proxy_pass http://127.0.0.1:1234;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
# this next line adds the Host header so that apache knows which vHost to serve
# the $host variable is automatically set to the hostname Nginx is responding to
proxy_set_header Host $host;
#Websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
2. Linux with Daphne
Make service-name.service
[Unit]
Description=Indifference Daphne Service
After=network.target
[Service]
Type=simple
User=indifference
WorkingDirectory=/home/indifference/path/to/indifference
ExecStart=/home/indifference/path/to/bin/daphne -p 3333 indifference.asgi:application
access-log=/data/logs/indifference/daphne/access.log
[Install]
WantedBy=multi-user.target
chmod 755 service-name.service
systemctl daemon-reload
systemctl enable service-name.service
systemctl start service-name.service
Update nginx.conf
upstream channels-indifference-backend {
server localhost:3333;
}
...
location /ws {
proxy_pass http://channels-indifference-backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
Still not working? Just restart it.
systemctl stop service-name.service
systemctl start service-name.service
systemctl status service-name.service
Windows Django - dev
Create a folder called config
config/
commonsettings.py
dev.py
prod.py
make sure that in dev.py and prod.py you import everything from commonsettings.py like this:
from .commonsettings import *
dev.py sample
INSTALLED_APPS = [
...
# 'channels',
...
]
ASGI_APPLICATION = None
then if you want to run the dev.py settings:
python manage.py runserver --settings=config.dev
In order to run your asgi application, simply point Daphne to your ASGI application, and optionally set a bind address and port (defaults to localhost, port 8000):
daphne -b 0.0.0.0 -p 9001 myproject.asgi:application
Nginx WS config is the same with 2. Linux with Daphne
* Use ASGI to deploy Django, StreamingHttpResponse cannot be accessed.
Async support for StreamingHttpResponse was only added in Django 4.2.
You can check the program with this:
https://www.phenomena.com/chat
Ref.