Evgenii Legotckoi
Evgenii Legotckoi25 жовтня 2018 р. 02: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
  • 04 серпня 2020 р. 02:19
  • (відредаговано)

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

Anton
  • 04 серпня 2020 р. 02:25

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

Anton
  • 05 серпня 2020 р. 04:20

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

Evgenii Legotckoi
  • 05 серпня 2020 р. 05:14

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
г
  • ги
  • 23 квітня 2024 р. 15:51

C++ - Тест 005. Структуры и Классы

  • Результат:41бали,
  • Рейтинг балів-8
l
  • laei
  • 23 квітня 2024 р. 09:19

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

  • Результат:10бали,
  • Рейтинг балів-10
l
  • laei
  • 23 квітня 2024 р. 09:17

C++ - Тест 003. Условия и циклы

  • Результат:50бали,
  • Рейтинг балів-4
Останні коментарі
k
kmssr08 лютого 2024 р. 18:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 01:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 10:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 08:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 грудня 2023 р. 21:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
Gar22 квітня 2024 р. 05:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 квітня 2024 р. 07:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 квітня 2024 р. 06:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 02:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex04 квітня 2024 р. 04:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Слідкуйте за нами в соціальних мережах