Django

⌘K
  1. Home
  2. Django
  3. chat
  4. User To User Chat
  5. Part 4: Designing the Database for Chat

Part 4: Designing the Database for Chat

Step-by-Step Instructions


Step 1: Define Chat Models

  1. Open the models.py file in the chat app 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

  1. 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

  1. 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

  1. Update the ChatConsumer in consumers.py to 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

  1. Update the user_list.html template 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>

How can we help?