Step-by-Step Instructions
Step 1: Define Chat Models
- Open the
models.pyfile in thechatapp and define the following models:
from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now
class ChatRoom(models.Model):
"""Represents a chat room."""
name = models.CharField(max_length=255, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Message(models.Model):
"""Represents a message in a chat room."""
user = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='messages')
content = models.TextField()
timestamp = models.DateTimeField(default=now)
def __str__(self):
return f'{self.user.username}: {self.content[:20]}'
Step 2: Create and Apply Migrations
- Run the following command to create migrations:
python manage.py makemigrations
Apply the migrations to update the database:
python manage.py migrate
Step 3: Add a Chat Room Creation Feature
- Add a view to create or get a chat room dynamically in
views.py:
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
from .models import ChatRoom
def get_or_create_room(request, room_name):
"""Fetch or create a chat room."""
room, created = ChatRoom.objects.get_or_create(name=room_name)
return JsonResponse({'room_name': room.name, 'created': created})
Update chat/urls.py to include this endpoint:
path('room/<str:room_name>/', views.get_or_create_room, name='get_or_create_room'),
Step 4: Add Messages to the Chat Room View
- Update the
ChatConsumerinconsumers.pyto handle database messages:
from .models import ChatRoom, Message
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
username = self.scope["user"].username
# Save message to the database
await self.save_message(username, self.room_name, message)
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'username': username,
}
)
async def chat_message(self, event):
message = event['message']
username = event['username']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'username': username,
}))
@sync_to_async
def save_message(self, username, room_name, message):
room = ChatRoom.objects.get(name=room_name)
user = User.objects.get(username=username)
Message.objects.create(user=user, room=room, content=message)
Step 5: Display Messages in the Frontend
- Update the
user_list.htmltemplate to include a link to chat rooms:
<h2>Users</h2>
<ul>
{% for user in users %}
<li>
<a href="/room/{{ user.username }}/">{{ user.username }}</a>
</li>
{% endfor %}
</ul>
<p><a href="{% url 'logout' %}">Logout</a></p>
Create a room.html template to display messages:
<h2>Room: {{ room_name }}</h2>
<div id="chat-log"></div>
<input id="chat-message-input" type="text" size="100">
<button id="chat-message-submit">Send</button>
<script>
const roomName = "{{ room_name }}";
const chatSocket = new WebSocket(
'ws://' + window.location.host + '/ws/chat/' + roomName + '/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').innerHTML += ('<p>' + data.username + ': ' + data.message + '</p>');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('chat-message-input');
const submitButton = document.getElementById('chat-message-submit');
// Trigger button click on Enter key press
input.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
event.preventDefault(); // Prevent the default action (e.g., form submission)
submitButton.click(); // Programmatically trigger the button click
}
});
// Submit message logic
submitButton.addEventListener('click', () => {
const message = input.value.trim();
if (message !== '') {
// Send message to WebSocket (using the correct chatSocket variable)
chatSocket.send(JSON.stringify({ 'message': message }));
input.value = ''; // Clear the input after sending
}
});
});
</script>