Evgenii Legotckoi
Evgenii Legotckoi25 октября 2018 г. 2:47

Django - Урок 039. Добавление личных сообщений и чатов на сайте - Часть 2 (Счётчик диалогов и чатов с непрочитанными сообщениями)

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

Раньше имелась очень большая недоработка, которая заключалась в том, что не показывался счётчик диалогов с непрочитанными сообщениями, что приводило к тому, что пользователей, которому присылали сообщение, просто не обращал на него внимания, поскольку не знал об этом сообщений.

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


Я размышлял над двумя вариантами организации счётчиков непрочитанных сообщений. Вернее одним вариантов и его более продвинутой версией.

  • При каждом запросе проверять все чаты, выбирать из них последние сообщения и проверять, является ли автором авторизованный пользователь, для которого нужно проверить данное сообщение. Если он не является автором, то проверяем, прочитано ли данное сообщение, если нет, то данный диалог для данного пользователя считаем непрочитанных. Количество таких диалогов будем считать количеством непрочитанных диалогов.
  • А второй вариант, на котором я остановился предполагает ту же самую логику, только диалог или чат должен иметь внешний ключ на самое последнее сообщение, которое было в него добавлено. Данный ключ будет обновляться при каждом новом сообщении. Тогда отпадает необходимость выборки сообщений по чату и их сортировки, чтобы получить самое последнее сообщение. Что, по-моему мнению может вылиться в большие накладные расходы для базы данных, если диалогов будет очень много.

Реализация

models.py

Добавим внешний ключ на последнее сообщение, а также а также кастомный менеджер для чатов ChatManager.

# -*- coding: utf-8 -*-

#... Код из предыдущей части


class ChatManager(models.Manager):
    use_for_related_fields = True

    # Метод принимает пользователя, для которого должна производиться выборка
    # Если пользователь не добавлен, то будет возвращены все диалоги,
    # в которых хотя бы одно сообщение не прочитано
    def unreaded(self, user=None):
        qs = self.get_queryset().exclude(last_message__isnull=True).filter(last_message__is_readed=False)
        return qs.exclude(last_message__author=user) if user else qs


class Chat(models.Model):
    #... Код из предыдущей части

    # внешний ключ на последнее сообщение,
    # важный момент в том, что название класса Message пишем обычной строкой,
    # поскольку на момент чтения класса Chat интерпретатор Python ничего не знает о классе Message
    # Также необходимо добавить related_name, имя через которое будет ассоциироваться выборка данного сообщения из базы данных
    last_message = models.ForeignKey('Message', related_name='last_message', null=True, blank=True, on_delete=models.SET_NULL)

    objects = ChatManager()

    @models.permalink
    def get_absolute_url(self):
        return 'users:messages', (), {'chat_id': self.pk }


class Message(models.Model):
    #... Код из предыдущей части

receivers.py

Я впервые пишу а таком файле Python в проекте на Django. Суть его в том, что там будут объявлены обработчики сигналов от модели. Дело в том, что в Django при сохранении объекта модели испускаются некоторые сигналы, которые можно обрабатывать. Это позволяет некоторую единообразную логику поместить в отдельный файл и сделать остальной код проекта несколько чище. Минусом является то, что данный код может быть неочевидным, поскольку никаких ссылок на данный код в других частях проекта не будет.

# -*- coding: utf-8 -*-

from django.db.models.signals import post_save
from django.dispatch import receiver

from users.models import Message


# обработчик сохранения объекта сообщения
@receiver(post_save, sender=Message)
def post_save_comment(sender, instance, created, **kwargs):
    # если объект был создан
    if created:
        # указываем чату, в котором находится данное сообщение, что это последнее сообщение
        instance.chat.last_message = instance
        # и обновляем данный внешний ключ чата
        instance.chat.save(update_fields=['last_message'])

Но просто так данный код не заработает, поскольку данный файл тоже нужно загрузить в интерпретатор.

Сделать это можно в файле apps.py при инициализации приложения

apps.py

Делается это в методе ready

# -*- coding: utf-8 -*-

from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _


class UsersConfig(AppConfig):
    name = 'users'
    verbose_name = _('Users')

    def ready(self):
        import users.receivers

Применение

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

context['unreaded_dialogs_counter'] = user.chat_set.unreaded(user=user).count()

Как исправить старые диалоги

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

admin.py

# -*- coding: utf-8 -*-

from django.contrib import admin

from users import models


class ChatAdmin(admin.ModelAdmin):
    autocomplete_fields = ['members']
    search_fields = ('members',)
    actions = ['fix_last_messages']

    def fix_last_messages(self, request, queryset):
        for chat in queryset.all():
            chat.last_message = chat.message_set.all().order_by('-pub_date').first()
            chat.save(update_fields=['last_message'])

    fix_last_messages.short_description = "Fix last messages"


class MessageAdmin(admin.ModelAdmin):
    autocomplete_fields = ['chat', 'author']
    list_display = ('chat', 'author', 'message', 'pub_date', 'is_readed')


admin.site.register(models.Chat, ChatAdmin)
admin.site.register(models.Message, MessageAdmin)
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

Anton
  • 4 августа 2020 г. 2:19
  • (ред.)

Здравствуйте, подскажите как именно должна выглядеть уже готовая вьюха с context? Не догоняю как его вставить

Anton
  • 4 августа 2020 г. 2:25

Может быть посоветуете как добавить необязательное поле + прокинуть его во вьюху что бы можно было отправлять небольшие документы.?

Anton
  • 5 августа 2020 г. 4:20

Этот вопрос я решил)

Evgenii Legotckoi
  • 5 августа 2020 г. 5:14

Добавляйте поле файла в модель сообщения. И в форме сообщения указывайте, что поле с файлом.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 26 октября 2024 г. 1:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 1:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
ИМ
Игорь Максимов22 ноября 2024 г. 11:51
Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 октября 2024 г. 14:37
Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 октября 2024 г. 8:19
Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5 октября 2024 г. 7:51
Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55 июля 2024 г. 11:02
QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Сейчас обсуждают на форуме
Evgenii Legotckoi
Evgenii Legotckoi24 июня 2024 г. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 ноября 2024 г. 6:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject4 июня 2022 г. 3:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 октября 2024 г. 9:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Следите за нами в социальных сетях