- Django Channels: уведомления в реальном времени
- Что я реализовал с помощью Channels?
- Что такое группы в Django Channels?
- Как я проектировал группы для индивидуальных пользователей?
- Структура сообщений¶
- Включение сообщений¶
- Настройка механизма сообщений¶
- Бэкенды для хранения данных¶
- Уровни сообщений¶
- Теги сообщений¶
- Django — Урок 029. Добавление личных сообщений и чатов на сайте — Часть 1
- Модели Chat и Message
- urls.py
- Форма сообщения
- Представления и шаблоны
- Отображение списка диалогов
- Текущий диалог и сообщения
- Начало беседы с пользователем
Django Channels: уведомления в реальном времени
Всякий раз, когда вы слышите слово «в реальном времени», первое, что приходит вам в голову (если вы разработчик), — это подключение к веб-сокету. Django не поддерживает веб-сокеты, и здесь на помощь приходят Django Channels.
Ниже приведены материалы для Django-каналов версии 2.x и Python версии 3.x.
Что я реализовал с помощью Channels?
- Задача — формировать уведомления и отправлять их в реальном времени с помощью сокетов.
- Чтобы упростить задачу, мы рассмотрим сценарий для одного пользователя. Предположим, что конкретное уведомление должно быть отправлено пользователю X, основная задача состоит в том, чтобы определить количество мест, из которых пользователь X вошел в систему, а затем отправить это уведомление всем им.
- Для этого я использую концепцию под названием Группа в Django Channels, и я могу отправлять уведомление во все места, фактически не зная количество мест, откуда X входит в систему. Давайте посмотрим, что такое группа в Django Channels.
Что такое группы в Django Channels?
- Группа — это набор соединений сокетов.
- Каждой группе присваивается уникальное имя.
- Channels идентифицируют соединение сокета, предоставляя ему уникальный ключ.
- Поэтому, когда вы добавляете соединение в группу, ключ этого соединения сохраняется в группе.
- Следовательно, Группа содержит все ключи различных соединений сокетов.
- Одно соединение сокета можно добавить в несколько групп.
- Преимущество группы состоит в том, что вы можете транслировать сообщение сразу всем соединениям группы.
- Чтобы добавить соединение в группу, используйте метод group_add уровня channel_layer , а для удаления соединения из группы используйте метод group_discard уровня канала.
- Вы можете транслировать сообщение на каналы в группе, используя метод group_send канального уровня.
- Если вы хотите узнать больше о том, что такое канальный слой, проверьте здесь.
Как я проектировал группы для индивидуальных пользователей?
- Каждый раз, когда пользователь входит в мою платформу, я использую Reconnecting WebSocket, чтобы открыть новое соединение сокета с Django-каналами.
- Я передаю токен аутентификации пользователя при подключении к сокету, а в бэкэнде использую этот токен для идентификации пользователя.
- Я также добавил свойство в свою модель User , чтобы сгенерировать имя группы для каждого пользователя. Ниже приведен код для него
- Теперь, когда новое соединение с сокетом выполняется с помощью ReconnectingWebSocket, Channels вызывают метод подключения моего потребителя. Узнать больше о потребителях.
- В этом методе подключения я определяю пользователя, получаю имя группы для этого пользователя и, наконец, добавляю новое подключение к этой группе с помощью метода group_add . Код смотрите в конце.
- Теперь, вспоминая сценарий, если я должен отправить уведомление конкретному пользователю X и X вошел в систему с 5 вкладок, мне просто нужно передать его в группе, и Django Channels сделают необходимое, чтобы отправить его на все вкладки.
- Вам может быть интересно, как удалить канал из группы, когда пользователь закрывает вкладку или выходит из системы. Поэтому всякий раз, когда пользователь закрывает вкладку, сокет автоматически отключается для этой вкладки, и если пользователь выходит из системы, я явно написал код, который отключает активное соединение сокета.
- Каждый раз, когда соединение закрывается, Django Channels вызывают метод отключения потребителя.
В этом методе отключения я использую метод group_discard для удаления соединения из группы. Смотрите фрагмент кода ниже.
Итак, используя Django Channels, я могу выполнить свою задачу по отправке уведомлений в режиме реального времени. Я также использовал каналы для создания приложения для обмена сообщениями в реальном времени, и оно работает без проблем.
Источник
Структура сообщений¶
Довольно часто в веб-приложениях требуется отобразить одноразовое уведомление (также известное как «флэш-сообщение») для пользователя после обработки формы или других типов пользовательского ввода.
Для этого Django обеспечивает полную поддержку обмена сообщениями на основе cookie и сессий, как для анонимных, так и для аутентифицированных пользователей. Фреймворк сообщений позволяет временно хранить сообщения в одном запросе и извлекать их для отображения в последующем запросе (обычно следующем). Каждое сообщение помечается определенным level , который определяет его приоритет (например, info , warning или error ).
Включение сообщений¶
Сообщения реализуются через класс middleware и соответствующий context processor .
По умолчанию settings.py , созданный django-admin startproject , уже содержит все настройки, необходимые для включения функции сообщений:
‘django.contrib.messages’ находится в INSTALLED_APPS .
MIDDLEWARE содержит ‘django.contrib.sessions.middleware.SessionMiddleware’ и ‘django.contrib.messages.middleware.MessageMiddleware’ .
По умолчанию storage backend полагается на sessions . Поэтому SessionMiddleware должен быть включен и появляться перед MessageMiddleware в MIDDLEWARE .
Опция ‘context_processors’ бэкенда DjangoTemplates , определенная в вашей настройке TEMPLATES , содержит ‘django.contrib.messages.context_processors.messages’ .
Если вы не хотите использовать сообщения, вы можете удалить ‘django.contrib.messages’ из вашего INSTALLED_APPS , строку MessageMiddleware из MIDDLEWARE и контекстный процессор messages из TEMPLATES .
Настройка механизма сообщений¶
Бэкенды для хранения данных¶
Фреймворк сообщений может использовать различные бэкенды для хранения временных сообщений.
Django предоставляет три встроенных класса хранения данных в django.contrib.messages :
class storage.session. SessionStorage ¶
Этот класс хранит все сообщения внутри сессии запроса. Поэтому для его работы требуется приложение Django contrib.sessions .
class storage.cookie. CookieStorage ¶
Этот класс хранит данные сообщения в cookie (подписанные секретным хэшем для предотвращения манипуляций) для сохранения уведомлений при разных запросах. Старые сообщения отбрасываются, если размер данных cookie превышает 2048 байт.
class storage.fallback. FallbackStorage ¶
Этот класс сначала использует CookieStorage , а затем возвращается к использованию SessionStorage для сообщений, которые не могут поместиться в одном cookie. Он также требует применения contrib.sessions от Django.
Это поведение позволяет избегать записи в сессию, когда это возможно. Это должно обеспечить наилучшую производительность в общем случае.
FallbackStorage — это класс хранения по умолчанию. Если он не подходит для ваших нужд, вы можете выбрать другой класс хранения, установив MESSAGE_STORAGE на его полный путь импорта, например:
Чтобы написать свой собственный класс хранения, подклассифицируйте класс BaseStorage в django.contrib.messages.storage.base и реализуйте методы _get и _store .
Уровни сообщений¶
Структура сообщений основана на архитектуре настраиваемых уровней, аналогичной модулю протоколирования Python. Уровни сообщений позволяют группировать сообщения по типу, чтобы их можно было фильтровать или по-разному отображать в представлениях и шаблонах.
Встроенные уровни, которые могут быть импортированы из django.contrib.messages напрямую, следующие:
Постоянная | Назначение |
---|---|
DEBUG | Сообщения, связанные с разработкой, которые будут проигнорированы (или удалены) в производственном развертывании |
INFO | Информационные сообщения для пользователя |
SUCCESS | Действие было выполнено успешно, например, «Ваш профиль был успешно обновлен». |
WARNING | Сбой не произошел, но может быть неизбежным |
ERROR | Действие было не успешным или произошел какой-то другой сбой |
Настройка MESSAGE_LEVEL может быть использована для изменения минимального уровня записи (или это может быть changed per request). Попытки добавить сообщения с уровнем меньше этого будут проигнорированы.
Теги сообщений¶
Теги сообщения — это строковое представление уровня сообщения плюс любые дополнительные теги, которые были добавлены непосредственно в представлении (подробнее см. ниже Adding extra message tags). Теги хранятся в строке и разделяются пробелами. Обычно теги сообщений используются как классы CSS для настройки стиля сообщения в зависимости от его типа. По умолчанию каждый уровень имеет один тег, который является строчной версией его собственной константы:
Уровень Постоянный | Метка |
---|---|
DEBUG | debug |
INFO | info |
SUCCESS | success |
WARNING | warning |
ERROR | error |
Чтобы изменить теги по умолчанию для уровня сообщения (встроенного или пользовательского), установите параметр MESSAGE_TAGS в словарь, содержащий уровни, которые вы хотите изменить. Так как это расширяет теги по умолчанию, вам нужно предоставить теги только для тех уровней, которые вы хотите отменить:
Источник
Django — Урок 029. Добавление личных сообщений и чатов на сайте — Часть 1
По сложившейся традиции расскажу о своих опытах по внедрению нового функционала на сайте. На данный момент этим функционалом являются личные сообщения между пользователями. Конечно, это сейчас работает не так хорошо, как в известных социальных сетях. но в итоге всё будет работать. Главное фидбек на форуме , пожалуйста.
Итак. Очень хотелось добавить личные сообщения на сайте, тем более, что я уже обмолвился об этом полгода назад. Оставался вопрос, как вообще это реализовать. При поиске по интернету удалось наткнуться на вариант, когда формируется следующая модель данных.
- Id сообщения
- from_user — отправитель
- to_user — получатель
- pub_date — дата сообщения
- message — контент сообщения
Попытался реализовать данный вариант, но меня остановило то, что вдруг после личных сообщений я захочу сделать чаты? Так почему бы сразу не заложить основу для чатов?
Модели Chat и Message
Это был бы отличный вариант для дальнейшего развития ресурса. Но в данном случае требуется создать две модели Chat и Message .
Если с моделью Message всё должно быть понятно. Есть текст сообщения, статус, было ли оно прочитано, автор сообщения и чат в который оно было отправлено, а также дата отправки сообщения.
То вот модель Chat несколько посложнее будет. Во-первых, чаты могут быть дух видов. Первый — это личная беседа двух человек. Второй вид — это коллективный чат. Зачем так было сделано? Это было необходимо для того, чтобы упростить поиск нужного чата, при отправки сообщения пользователю с его личной страницы. К сожалению на данный момент сделан только такой способ отправить первое сообщение пользователю. То есть зайти на его страницу и кликнуть кнопку написать сообщение. В дальнейшем можно будет находить пользователя со страницы диалогов на вашей личной странице. Это пока временные ограничения в рамках первой User Story , которую я себе написал.
Каждый чат имеет many-to-many связь, которая отвечает за список участников в рамках чата. Благодаря этому можно ограничить просмотр чатов, а также возможность писать в чаты, если пользователь не был приглашён в данный чат.
urls.py
Какие вьюшки нам понадобятся и какие маршруты можно сделать? Мне на реализацию данного функционала в самом простом виде понадобилось написать три вьюшки и соответственно три маршрута в urls.py.
Не будем углубляться в каком именно приложении будем использовать данные маршруты — это не принципиально.
По факту здесь имеется три вьюшки, одна для списка диалогов у пользователя, другая для создания диалога со страницы другого пользователя, а третья для сообщений в диалоге.
Форма сообщения
В данном случае можно использовать форму для модели. Укажем модель, а также какие поля должны быть отображены с удалением лейбла у поля ввода.
По умолчанию у вас будет обычная textarea. Я использую свой самописный WYSIWYG редактор.
Представления и шаблоны
Отображение списка диалогов
Для получения списка всех диалогов, в которых задействован пользователь, необходимо провести фильтрацию всех чатов по участникам, то есть по Many-toMany полю members.
В данном случае у меня меня имеется шаблон для диалогов, в который я передаю авторизованного пользователя и список чатов. Активный пользователь будет нужен для корректного отображения прочитанных и не прочитанных сообщений в списке диалогов.
Наибольший интерес представляет сам список диалогов и его вёрстка, поэтому из шаблона здесь будет представлена только та часть, которая отвечает за вёрстку.
Вы можете заметить в шаблоне мой пользовательский встраиваемый тег. Данный тег отвечает за то, чтобы вернуть собеседника в диалоге, чтобы отталкиваясь от информации о собеседнике сформировать адекватную вёрстку для списка диалогов и указание прочитанных и непрочитанных сообщений в списке диалогов.
Таким образом список диалогов будет выглядеть следующим образом:
Текущий диалог и сообщения
Для отображения текущего диалога и сообщений уже потребуется более сложная логика. Дело в том, что здесь доступ к чату осуществляется по ID, но необходимо сделать не только попытку получения диалога, но и проверить, существует ли в списке участников пользователь, который пытается попасть в данный чат. Если он не существует в списке участников, то доступ в данный чат ему запрещён. Помимо прочего в этом же представлении обрабатывается отсылка сообщений и пометка сообщений прочитанными.
Шаблон списка сообщений
Шаблон самого сообщения
Пример получившегося диалога
Начало беседы с пользователем
На данный момент реализован лишь один метод для начала беседы с пользователем. Необходимо перейти на страницу пользователя и нажать на кнопку «Написать сообщение», тогда через ссылку будет отправлен запрос, в котором будет создан чат или найден уже существующий чат с этим пользователем. Здесь испольуется проверка на то, является ли чат диалогом или беседой нескольких пользователей. Что позволяет несколько упростить поиск необходимого диалога.
Обязательно делаем проверку на количество пользователей, поскольку в личной беседе может быть только два пользователя, ну и проверяем, чтобы этими пользователями был наш авторизованный пользователей, а также пользователь с которым мы пытаемся начать беседу.
После того, как чат создан, делаем переадресацию на страницу сообщений.
Для Django рекомендую VDS-сервера хостера Timeweb .
Рекомендуем хостинг TIMEWEB
Рекомендуемые статьи по этой тематике
Источник