Невозможно сохранить сообщения чата с помощью django и websocket

Я следовал этому руководству, чтобы создать функцию чата между двумя пользователями, используя Django и WebSockets/Channels: https://www.youtube.com/watch?v=lHGcSOkrKw0&t=122s&ab_channel=AaravTech

Все работает нормально, кроме сохранения сообщений чата. Когда я обновляю страницу, чат исчезает. При проверке базы данных экземпляр потока создается, но в него ничего не сохраняется. Это просто пустой {}. Экземпляр потока может быть вызван и имеет ID. Когда я пытаюсь соединиться с пользователем, с которым я уже соединился, новый экземпляр потока не создается

app_chat/managers.py

from django.db import models
from django.db.models import Count


class ThreadManager(models.Manager):
    def get_or_create_personal_thread(self, user1, user2):
        threads = self.get_queryset().filter(thread_type='personal')
        threads = threads.filter(users__in=[user1, user2]).distinct()
        threads = threads.annotate(u_count=Count('users')).filter(u_count=2)
        if threads.exists():
            return threads.first()
        else:
            thread = self.create(thread_type='personal')
            thread.users.add(user1)
            thread.users.add(user2)
            return thread

    def by_user(self, user):
        return self.get_queryset().filter(users__in=[user])

app_chat/models.py

from django.db import models
from app_users.models import User
from app_chat.managers import ThreadManager


class TrackingModel(models.Model):
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class Thread(TrackingModel):
    THREAD_TYPE = (
        ('personal', 'Personal'),
        ('group', 'Group')
    )

    name = models.CharField(max_length=50, null=True, blank=True)
    thread_type = models.CharField(
        max_length=15, choices=THREAD_TYPE, default='group')
    users = models.ManyToManyField(User)

    objects = ThreadManager()

    def __str__(self):
        if self.thread_type == 'personal' and self.users.count() == 2:
            return f'{self.users.first()} and {self.users.last()}'
        return f'{self.name}'


class Message(TrackingModel):
    thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
    sender = models.ForeignKey(User, on_delete=models.CASCADE)
    text = models.TextField(blank=False, null=False)

    def __str__(self) -> str:
        return f'From <Thread - {self.thread}>'

app_chat/consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from app_users.models import User
from app_chat.models import Thread, Message
from asgiref.sync import sync_to_async
from channels.db import database_sync_to_async


class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        me = self.scope['user']
        other_username = self.scope['url_route']['kwargs']['username']
        other_user = await sync_to_async(User.objects.get)(username=other_username)
        self.thread_obj = await sync_to_async(Thread.objects.get_or_create_personal_thread)
        (me, other_user)
        self.room_name = f'personal_thread_{self.thread_obj.id}'
        self.room_group_name = 'chat_%s' % self.room_name

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()
        print(f"Connected to server == {self.thread_obj}")

    async def disconnect(self, close_code):
        # Leave group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        username = text_data_json['username']
        # Send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
                'username': username,
            }
        )
        print(f'{username} : {message} Message recieved')
        await self.store_message(message)

    # Receive message from room group
    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,
        }))
        print(f'{username} : {message} Message recieved')

    @database_sync_to_async
    def store_message(self, message):
        new_message = Message.objects.create(
            thread=self.thread_obj,
            sender=self.scope['user'],
            text=message
        )
        print(f'Message stored')
        new_message.save()

Я думаю, что проблема может быть связана с self.thread_obj в файле consumper.py. Когда я добавляю print(f "Connected to server == {self.thread_obj}"), я получаю ошибку, описанную ниже. Без print ошибки нет, а сохранение все равно не работает.

HTTP GET /chat/mickeykbp/ 200 [0.05, 127.0.0.1:50331]
WebSocket HANDSHAKING /ws/chat/mickeykbp/ [127.0.0.1:50333]
Exception inside application: object SyncToAsync can't be used in 'await' expression
Traceback (most recent call last):
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\staticfiles.py", line 44, in __call__
    return await self.application(scope, receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\routing.py", line 71, in __call__
    return await application(scope, receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\sessions.py", line 47, in __call__
    return await self.inner(dict(scope, cookies=cookies), receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\sessions.py", line 263, in __call__
    return await self.inner(wrapper.scope, receive, wrapper.send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\auth.py", line 185, in __call__
    return await super().__call__(scope, receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\middleware.py", line 26, in __call__
    return await self.inner(scope, receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\routing.py", line 150, in __call__
    return await application(
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\consumer.py", line 94, in app
    return await consumer(scope, receive, send)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\consumer.py", line 58, in __call__
    await await_many_dispatch(
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\utils.py", line 51, in await_many_dispatch
    await dispatch(result)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\consumer.py", line 73, in dispatch
    await handler(message)
  File "C:\Users\Anouphong\.virtualenvs\project_homecook-l563S6IX\lib\site-packages\channels\generic\websocket.py", line 173, in websocket_connect
    await self.connect()
  File "C:\Users\Anouphong\Desktop\coding\project_homecook\project_homecook\app_chat\consumers.py", line 15, in connect
    self.thread_obj = await sync_to_async(Thread.objects.get_or_create_personal_thread)
TypeError: object SyncToAsync can't be used in 'await' expression
WebSocket DISCONNECT /ws/chat/mickeykbp/ [127.0.0.1:50333]
Вернуться на верх