Ошибка Websocket-соединения в Django и ошибка "Пользователь, соответствующий запросу, не существует

Я пытаюсь создать приложение для чата один на один, используя django channels, websockets и Redis.Пробовал реализовать django channels из (https://youtu.be/RVH05S1qab8), но получаю ошибки вроде этой (из консоли javaScript).Строка 253 из views.py, код которой приведен ниже.Также ошибка в строке 95 models.py, которая также приведена в коде ниже.

(от терминала)

Также сообщение не отправляется другому пользователю в реальном времени, и страницу приходится обновлять, чтобы получить сообщение.

Код для thread.html:


    {% extends "bookexchange/base.html" %}
    
    {% block content %}
    <h3>Thread for {% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}</h3>
    <ul id='chat-items'>
    {% for chat in object.chatmessage_set.all %}
    
    <li>{{ chat.message }} via {{ chat.user }}</li>
    
    {% endfor %}
    </ul>
    
    <form id='form' method='POST'> {% csrf_token %}
        <input type="hidden" id="myUsername" value="{{ user.username }}">
    {{form.as_p }}
    <input type='submit' class='btn btn-primary'/>
    </form>
    
    {% endblock %}
    
    {% block script %}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js" integrity="sha512-B4skI5FiLurS86aioJx9VfozI1wjqrn6aTdJH+YQUmCZum/ZibPBTX55k5d9XM6EsKePDInkLVrN7vPmJxc1qA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <script>
    
    var loc=window.location
    var formData=$("#form")
    var msgInput=$("#id_message")
    var chatHolder=$("#chat-items")
    var me=$("#myUsername").val()
    var wsStart='ws://' 
    if(loc.protocol=='https:'){
        wsStart='wss://'
    }
    var endpoint =wsStart + loc.host + loc.pathname 
    var socket= new WebSocket(endpoint)
    
    socket.onmessage=function(e){
        console.log("message",e)
        var chatDataMsg=JSON.parse(e.data)
        chatHolder.append("<li>"+ chatDataMsg.message +"via"+ chatDataMsg.username +"</li>")
    }
    socket.onopen=function(e){
        console.log("open",e)
        formData.submit(function(event){
            event.preventDefault()
            var msgText=msgInput.val()
            // chatHolder.append("<li>"+ msgText + " via "+me  + "</li>")
            // var formDataSerialized=formData.serialize()
            var finalData={
                'message': msgText
            }
            socket.send(JSON.stringify(finalData))
            // msgInput.val('')
            formData[0].reset()
        })
    }
    socket.onerror=function(e){
        console.log("error",e)
    }
    socket.onclose=function(e){
        console.log("close",e)
    }
    
    </script>
    {% endblock %}

Код для consumers.py:


import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async
from .models import Thread,ChatMessage


class ChatConsumer(AsyncConsumer):
    async def websocket_connect(self,event):
        print("connected",event)
        
        other_user=self.scope['url_route']['kwargs']['username']
        me = self.scope['user']
        # print(other_user,me)
        thread_obj=await self.get_thread(me,other_user)
        print(me,thread_obj.id)
        self.thread_obj=thread_obj
        chat_room=f"thread_{thread_obj.id}"
        self.chat_room=chat_room
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )

        await self.send({
            'type':"websocket.accept"
        })
        # await asyncio.sleep(10)
       
    async def websocket_receive(self,event):
        print("receive",event)
        front_text=event.get('text',None)
        if front_text is not None:
            loaded_dict_data=json.loads(front_text)
            msg=loaded_dict_data.get('message')
          
            user=self.scope['user']
            username='default'
            if user.is_authenticated:
                username=user.username
            myResponse={
                'message':msg,
                'username':username
            }
            await self.create_chat_message(user,msg)
            await self.channel_layer.group_send(
                self.chat_room,
                # new_event
                {
                    'type':"chat_message",
                    "text":json.dumps(myResponse)
                }
            )
    async def chat_message(self,event):
        print('message',event)
        await self.send({
            'type':"chat_message",
            "text":event['text']
        })

            

    async def websocket_disconnect(self,event):
        print("disconnected",event)
    
    @database_sync_to_async
    def get_thread(self,user,other_username):
        return Thread.objects.get_or_new(user,other_username)[0]

    @database_sync_to_async
    def create_chat_message(self,me,msg):
        thread_obj=self.thread_obj
        me=self.scope['user']
        return Thread.objects.create(thread=thread_obj,user=me,message=msg)

Код для views.py:


class ThreadView(LoginRequiredMixin, FormMixin, DetailView):
    template_name = 'bookexchange/thread.html'
    form_class = ComposeForm
    success_url = './'

    def get_queryset(self):
        return Thread.objects.by_user(self.request.user)

    def get_object(self):
        other_username  = self.kwargs.get("username")
        obj, created  = Thread.objects.get_or_new(self.request.user,other_username) #line 253
        if obj == None:
            raise Http404
        return obj

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.get_form()
        return context

Models.py содержит модель User, созданную с помощью AbstractUser. Также он содержит функцию 'broadcast_msg_to_chat', которая не определена нигде в исходном коде. Код имеет следующий вид


class ThreadManager(models.Manager):
        def by_user(self, user):
            qlookup = Q(first=user) | Q(second=user)
            qlookup2 = Q(first=user) & Q(second=user)
            qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
            return qs
    
        def get_or_new(self, user, other_username): # get_or_create
            username = user.username
            if username == other_username:
                return None
            qlookup1 = Q(first__username=username) & Q(second__username=other_username)
            qlookup2 = Q(first__username=other_username) & Q(second__username=username)
            qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
            if qs.count() == 1:
                return qs.first(), False
            elif qs.count() > 1:
                return qs.order_by('timestamp').first(), False
            else:
                Klass = user.__class__
                user2 = Klass.objects.get(username=other_username) #line 95
                if user != user2:
                    obj = self.model(
                            first=user, 
                            second=user2
                        )
                    obj.save()
                    return obj, True
                return None, False
    
    
    class Thread(models.Model):
        first        = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
        second       = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
        updated      = models.DateTimeField(auto_now=True)
        timestamp    = models.DateTimeField(auto_now_add=True)
        
        objects      = ThreadManager()
    
        @property
        def room_group_name(self):
            return f'chat_{self.id}'
    
        def broadcast(self, msg=None):
            if msg is not None:
                broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
                return True
            return False
    
    
    class ChatMessage(models.Model):
        thread      = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
        user        = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
        message     = models.TextField()
        timestamp   = models.DateTimeField(auto_now_add=True)

Код для routing.py:


    application= ProtocolTypeRouter({
        'websocket':AllowedHostsOriginValidator(
            AuthMiddlewareStack(
                URLRouter(
                    [
                        re_path(r"^messages/(?P<username>[\w.@+-]+)/$", ChatConsumer),
                    ]
                )
            )
        )
    })

Вернуться на верх