How to make chat application in django
Posted By : Dinesh Kumar | 29-Jul-2022
There are file structures of django framework.
There are some main commands that are used in django application creation.
1. create application run command -
$ django-admin startproject projectName
2. create app inside project -
$ python manage.py createapp appName
3. Run server -
$ python manage.py runserver
Django working flow-
Models.py
from django.db import models from django.contrib.auth import get_user_model from django.db.models import Q User = get_user_model() # Create your models here. class ThreadManager(models.Manager): def by_user(self, **kwargs): user = kwargs.get('user') lookup = Q(first_person=user) | Q(second_person=user) qs = self.get_queryset().filter(lookup).distinct() return qs class Thread(models.Model): first_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='thread_first_person') second_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='thread_second_person') updated = models.DateTimeField(auto_now=True) timestamp = models.DateTimeField(auto_now_add=True) objects = ThreadManager() class Meta: unique_together = ['first_person', 'second_person'] class ChatMessage(models.Model): thread = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.CASCADE, related_name='chatmessage_thread') user = models.ForeignKey(User, on_delete=models.CASCADE) message = models.TextField() timestamp = models.DateTimeField(auto_now_add=True)
views.py
from django.contrib.auth.decorators import login_required from django.shortcuts import render from django.http import HttpResponse, JsonResponse import json # Create your views here. from chat.models import Thread # @login_required def messages_page(request): # threads = Thread.objects.by_user(user=request.user).prefetch_related('chatmessage_thread').order_by('timestamp') threads = '' context = { 'Threads': threads } return render(request, 'messages.html', context) def test(request): if not request.body: return JsonResponse(status=200, data={'message': 'No request body'}) body = json.loads(bytes(request.body).decode('utf-8')) if 'username' not in body: return JsonResponse(status=400, data={'message': 'Username is required to join the channel'}) username = body['username']
urls.py
from django.urls import path from . import views urlpatterns = [ path('message', views.messages_page), path('', views.test, name='test') ]
myproject/urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('chat/', include('chat.urls')) ]
routers.py
from django.urls import path from . import consumers websocket_urlpatterns = [ path('chat/', consumers.ChatConsumer.as_asgi()), ]
consumers.py
import json from channels.consumer import AsyncConsumer from channels.db import database_sync_to_async from django.contrib.auth import get_user_model from chat.models import Thread, ChatMessage User = get_user_model() class ChatConsumer(AsyncConsumer): async def websocket_connect(self, event): print('connected', event) user = self.scope['user'] chat_room = f'user_chatroom_{user.id}' self.chat_room = chat_room await self.channel_layer.group_add( chat_room, self.channel_name ) await self.send({ 'type': 'websocket.accept' }) async def websocket_receive(self, event): print('receive', event) received_data = json.loads(event['text']) msg = received_data.get('message') sent_by_id = received_data.get('sent_by') send_to_id = received_data.get('send_to') thread_id = received_data.get('thread_id') if not msg: print('Error:: empty message') return False sent_by_user = await self.get_user_object(sent_by_id) send_to_user = await self.get_user_object(send_to_id) thread_obj = await self.get_thread(thread_id) if not sent_by_user: print('Error:: sent by user is incorrect') if not send_to_user: print('Error:: send to user is incorrect') if not thread_obj: print('Error:: Thread id is incorrect') await self.create_chat_message(thread_obj, sent_by_user, msg) other_user_chat_room = f'user_chatroom_{send_to_id}' self_user = self.scope['user'] response = { 'message': msg, 'sent_by': self_user.id, 'thread_id': thread_id } await self.channel_layer.group_send( other_user_chat_room, { 'type': 'chat_message', 'text': json.dumps(response) } ) await self.channel_layer.group_send( self.chat_room, { 'type': 'chat_message', 'text': json.dumps(response) } ) async def websocket_disconnect(self, event): print('disconnect', event) async def chat_message(self, event): print('chat_message', event) await self.send({ 'type': 'websocket.send', 'text': event['text'] }) @database_sync_to_async def get_user_object(self, user_id): qs = User.objects.filter(id=user_id) if qs.exists(): obj = qs.first() else: obj = None return obj @database_sync_to_async def get_thread(self, thread_id): qs = Thread.objects.filter(id=thread_id) if qs.exists(): obj = qs.first() else: obj = None return obj @database_sync_to_async def create_chat_message(self, thread, user, msg): ChatMessage.objects.create(thread=thread, user=user, message=msg)
admin.py
from django.contrib import admin from django import forms from django.core.exceptions import ValidationError from django.db.models import Q from .models import Thread, ChatMessage admin.site.register(ChatMessage) class ChatMessage(admin.TabularInline): model = ChatMessage class ThreadAdmin(admin.ModelAdmin): inlines = [ChatMessage] class Meta: model = Thread admin.site.register(Thread, ThreadAdmin)
settings.py
import os.path from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-il2i31l!d$kn*!=ro18w*5-)(^pttckg0*-gp!u7g+=o4z$(+j' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ALLOWED_HOSTS = ['*'] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'chat', 'channels', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'myproject.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] # WSGI_APPLICATION = 'myproject.wsgi.application' ASGI_APPLICATION = 'myproject.asgi.application' # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': BASE_DIR / 'db.sqlite3', # } # } DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # 'ENGINE': 'django.db.backends.postgresql_psycopg2', # 'NAME': 'channelsdb', # 'USER': 'omkar', # 'PASSWORD': '2311', # 'HOST': 'localhost', # 'PORT': '', } } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels.layers.InMemoryChannelLayer', # 'CONFIG': { # 'hosts': [('127.0.0.1', 6379)], # } } }
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
Dinesh Kumar
Dinesh Kumar is working as a Front-End developer. He has expertise in Angular, HTML and CSS. He is a quick learner with great adaptability.