логика сохранения объекта уведомления django websockets - PullRequest
1 голос
/ 02 мая 2019

Мне трудно обдумать, как сохранять уведомления при получении сообщения от другого other_user в приложении чата для 2 человек Django Channels websockets.

Сейчас у меня есть функция def create_notification, которая вызывается после def create_chat_message.

def create_chat_message создает новый объект ChatMessage каждый раз, когда в Thread отправляется новое сообщение. Требуются аргументы thread=thread_obj, user=me, message=msg Таким образом, очевидно, что каждое отдельное сообщение сохраняется вместе с пользователем, который его отправил.

def create_notification берет последний объект id в ChatMessage и создает новый Notification объект.

created_notification = Notification.objects.create(notification_user=user, notification_chat=last_chat)

Таким образом, человек, отправляющий сообщение, связан с полем notification_user в модели Notification и сохраняется вместе с идентификатором ChatMessage.

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

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

Как я могу отсылать все уведомления для каждой темы, в которой я нахожусь, с различными пользователями?

Я сохраняю это неправильно? Должен ли я настроить функцию сохранения уведомлений так, чтобы она сохраняла только входящие сообщения от другого пользователя? Или добавить какой-нибудь if statement?

Разве мне не нужно каким-либо образом связываться с уведомлением, чтобы при их выводе отображались все уведомления, где я получатель?

Моя Notification модель имеет ChatMessage в виде ForeignKey с полем thread, которое содержит ForeignKey до Thread, которое содержит first и second (представляет меня и другого пользователя) в один поток).

Я смотрю на это уже несколько дней и чувствую, что упускаю что-то простое и делаю это намного сложнее, чем нужно.

* * Models.py тысяча сорок-девять
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

    # method to grab the thread for the 2 users
    def get_or_new(self, user, other_username): # get_or_create
        username = user.username
        if username == other_username:
            return None, None
        # looks based off of either username
        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__
            try:
                user2 = Klass.objects.get(username=other_username)
            except Klass.DoesNotExist:
                user2 = None
            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()

    def __str__(self):
        return f'{self.id}'

    @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)

    def __str__(self):
        return f'{self.id}'

class Notification(models.Model):
    notification_user = models.ForeignKey(User, on_delete=models.CASCADE)
    notification_chat = models.ForeignKey(ChatMessage, on_delete=models.CASCADE)
    notification_read = models.BooleanField(default=False)

    def __str__(self):
        return f'{self.id} attached to {self.notification_user}'

consumers.py

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)
        self.thread_obj = thread_obj
        chat_room = f"thread_{thread_obj.id}"
        self.chat_room = chat_room
        # below creates the chatroom
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )

        await self.send({
            "type": "websocket.accept"
        })

    async def websocket_receive(self, event):
        # when a message is recieved from the websocket
        print("receive", event)

        message_type = json.loads(event.get('text','{}')).get('type')
        print(message_type)
        if message_type == "notification_read":
            user = self.scope['user']
            username = user.username if user.is_authenticated else 'default'
            # Update the notification read status flag in Notification model.
            notification = Notification.objects.filter(notification_user=user)
            notification.notification_read = True
            notification.save()  #commit to DB
            print("notification read")
            return

        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 = user.username if user.is_authenticated else 'default'
            notification_id = 'default'
            myResponse = {
                'message': msg,
                'username': username,
                'notification': notification_id,
            }
            print(myResponse)
            await self.create_chat_message(user, msg)
            await self.create_notification(user, msg)

            # broadcasts the message event to be sent, the group send layer
            # triggers the chat_message function for all of the group (chat_room)
            await self.channel_layer.group_send(
                self.chat_room,
                {
                    'type': 'chat_message',
                    'text': json.dumps(myResponse)
                }
            )

    # chat_method is a custom method name that we made
    async def chat_message(self, event):
        # sends the actual message
        await self.send({
                'type': 'websocket.send',
                'text': event['text']
        })

    async def websocket_disconnect(self, event):
        # when the socket disconnects
        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
        return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)

    @database_sync_to_async
    def create_notification(self, user, msg):
        last_chat = ChatMessage.objects.latest('id')
        created_notification = Notification.objects.create(notification_user=user, notification_chat=last_chat)
        print(created_notification)
        return created_notification

navbar.html

  <div id="notificationsBody" class="notifications">
              {% for notifications in notification|slice:"0:10" %}
              <a href="{% url 'chat:thread' user %}">
                <span id="notification-{{notification.id}}">
                  {{ notifications.notification_chat.message }}
                  via {{ notifications.notification_chat.user }}
                  at {{ notifications.notification_chat.timestamp }}
                </span>
              </a>
              {% endfor %}

1 Ответ

1 голос
/ 02 мая 2019

Объект Notification, который вы создаете, необходимо установить Notification.notification_user на other_user.Уведомление предназначено для другого пользователя, а не для пользователя, отправившего сообщение.

other_username = self.scope['url_route']['kwargs']['username']
other_user = User.objects.get(username=other_username)
await self.create_notification(other_user, msg)  #other_user, not the current user

Однако при обновлении Notification как прочитанного требуется текущий пользователь.

...