0

I'm doing a course from YouTube "Python Django Realtime Chat Project - Full Course" and I'm new to django.My problem is, When I try to send message in room chat (submit form) I get this error Forbidden (403) CSRF verification failed. We don't have CSRFtoken in our form in room.html but The instructor fixed the error by adding e.preventDefault(); and return false; in submit querySelector block in room.html. I still get the error. when submitting the form message should add to div with chat-messages id.

room.html:


{% extends 'core/base.html' %}
{% block title %}
{{room.name}}
{% endblock %}
{% block content %}
<div class="p-10 lg:p-20 text-center">
    <h1 class="text-3xl lg:text-6xl text-white">{{room.name}}</h1>
</div>

<div class="lg:w-2/4 mx-4 lg:mx-auto p-4 bg-white rounded-xl">
    <div class="chat-messages space-y-3" id="chat-messages">
        <div class="p-4 bg-gray-200 rounded-xl">
            <p class="font-semibold">Username</p>
            <p>Message.</p>
        </div>
    </div>
</div>


<div class="lg:w-2/4 mx-4 lg:mx-auto p-4 bg-white rounded-xl">
<form method='POST' action='.' class='flex'>

    <input type="text" name="content" class="flex-1 mr-3" placeholder="Your message..." id="chat-message-input">
    <button class="px-5 py-3 rounded-xl text-white bg-teal-600 hover:bg-teal-700" id="chat-message-submit">
        send
    </button>
</form>
</div>
{% endblock  %}
{% block script %}
{{room.slug|json_script:"json-roomname"}}
{{request.user.username|json_script:"json-username"}}
<script>
    const roomName = JSON.parse(document.getElementById('json-roomname').textContent);
    const userName = JSON.parse(document.getElementById('json-username').textContent);

    const chatSocket = new WebSocket(
        'ws://'
        + window.location.host
        + '/ws/'
        + roomName
        + '/'
    );
    chatSocket.onmessage = function(e) {
        console.log('onmessage')
        const data =  JSON.parse(e.data);
        if (data.message){
            let html = '<div class="p-4 bg-gray-200 rounded-xl">';
                html += '<p class="font-semibold">'+ data.username +'</p>';
                html += '<p>'+ data.message +'</p></div>';
            document.querySelector('#chat-messages').innerHTML += html;

        }else {
            alert('Type something!')
        }
    }
    chatSocket.onclose = function(e) {
        console.log('onclose')
    }
    document.querySelector('#chat-message-submit').onclick = function(e){
        e.preventDefault();
        const messageInputDom = document.querySelector('#chat-message-input');
        const message = messageInputDom.value;
        chatSocket.send(JSON.stringify({
            'message': message,
            'username': userName,
            'room': roomName,
        }));
        messageInputDom.value = '';
        return false;
    }
</script>
{% endblock %}


consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async


class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()

    async def disconnect(self):
        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 = data['username']
        room = data['room']
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
                'username': username,
                'room': room,

            }
        )

    async def chat_message(self, event):
        message = event['message']
        username = event['username']
        room = event['room']

        await self.send(text_data=json.dumps({
            'message': message,
            'username': username,
            'room': room,

        }))

routing.py

from django.urls import path
from . import consumers
websocket_urlpatterns = [
    path('ws/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
]

views

from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import Room
# Create your views here.


@login_required
def rooms(request):
    rooms = Room.objects.all()
    return render(request, 'room/rooms.html', {'rooms': rooms})


@login_required
def room(request, slug):
    room = Room.objects.get(slug=slug)
    return render(request, 'room/room.html', {'room': room})

url

from django.urls import path
from . import views
urlpatterns = [
    path('', views.rooms, name='rooms'),
    path('<slug:slug>/', views.room, name="room"),
]

error when I add the token, I don't get the error but the message also does not add to html. It's like nothing happens. structure

Help
  • 1
  • 5
  • You can just simply remove `action="."` as Django always takes current page route, so it will work without `action` attribute too. – Sunderam Dubey Nov 19 '22 at 11:07
  • I did and it still doesn't work. – Help Nov 19 '22 at 11:31
  • Which error you are currently facing? – Sunderam Dubey Nov 19 '22 at 11:33
  • the error I asked. But when I add the token, I no longer get the error instead it does not work no message sends. Like I write the text and submit but nothing happens. I added type submit to button and still no change. – Help Nov 19 '22 at 11:37
  • Remove `{% csrf_token %}` from html and add `@csrf_exempt` decorator on `room` view just below the `@login_required` decorator, if don't need security against csrf forgery. – Sunderam Dubey Nov 19 '22 at 11:47
  • I did and it's not working. Ok I think the problem is somewhere else because now that I no longer get the error, I also don't get console.log('onmessage') in chatSocket.onmessage – Help Nov 19 '22 at 11:58
  • After adding @csrf_exempt decorator does the main error solved? – Sunderam Dubey Nov 19 '22 at 11:59
  • I found a Very good [question](https://stackoverflow.com/q/53176767) you should see, so you can remove `{% csrf_token %}` and add `@csrf_exempt` decorator on view. – Sunderam Dubey Nov 19 '22 at 12:02
  • Yes, I also knew I had to add csrf in form or as decorator for this error but the instructor did not do that and solved the problem as I mentioned in the question. Now I have another problem which I thought it happens because of me adding the token myself, and the problem is the reason why he did not, but it seems that's the only way and my problem is either logical or typo which I have no Idea since I did it step by step with him. Thank you, I will get back to it later and maybe I redo it. If I fix the problem I will answer myself. :) – Help Nov 19 '22 at 12:11

1 Answers1

1

Simply you can add csrf_token inside form tag of template.

In template:

<form>
   {% csrf_token %}  
</form>

And that error will solve.

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Manoj Tolagekar
  • 1,816
  • 2
  • 5
  • 22