Обновление Django для получения новых сообщений для пользователя.

Я пытаюсь сделать простой протокол push для сообщений Django. Итак, в моем вызове REST у меня есть следующий фрагмент:

    storage = get_messages(self.request)
    res = dict(messages=[dict(level=item.level, message=item.message) for item in storage])

    now = monotonic()
    while not res.messages and monotonic() - now < 15:
        sleep(.5)
        res.messages = [dict(level=item.level, message=item.message) for item in storage]

Естественно, цикл while ничего не делает, потому что среда сообщений просто перечитывает переменную сеанса, которая только "обновляет" новые запросы.

Я попытался заглянуть в основной код, чтобы узнать, было ли что-нибудь об обновлении хранилища на лету, но, похоже, нет кода, который бы делал это, по крайней мере, в среде обмена сообщениями. Был этот многообещающий недокументированный storage.update() метод, но оказалось, сделать что-то еще.

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

1 ответ

Решение

Мне удалось прийти к приемлемому решению с несколькими оговорками. Использование существующих хранилищ сообщений (cookie или сеанс) оказалось либо невозможным (cookie), либо слишком перегруженным внутренними вызовами методов и установкой / удалением внутренних участников (сеанс).

Это решение использует новое хранилище сообщений, в моем случае - базу данных.

settings.py

MESSAGE_STORAGE = 'your_django_app.messages_store.SessionDBStorage'

your_django_app / messages_store.py

from django.contrib.messages.storage.session import SessionStorage
from main.models import MessagesStore, models


class SessionDBStorage(SessionStorage):
    """
    Stores messages in the database based on session id
    """

    def _get(self, *args, **kwargs):
        """
        Retrieves a list of messages from the database based on session identifier.
        """
        try:
            return self.deserialize_messages(
                MessagesStore.objects.get(pk=self.request.session.session_key).messages), True
        except models.ObjectDoesNotExist:
            return [], True

    def _store(self, messages, response, *args, **kwargs):
        """
        Stores a list of messages to the database.
        """
        if messages:
            MessagesStore.objects.update_or_create(session_key=self.request.session.session_key,
                                                   defaults={'messages': self.serialize_messages(messages)})
        else:
            MessagesStore.objects.filter(pk=self.request.session.session_key).delete()
        return []

your_django_app / rest.py

def pushed_messages():
    from time import sleep, monotonic
    # standard get messages code
    ....
    now = monotonic()
    while not res.messages and monotonic() - now < 15:
        sleep(1)
        if hasattr(storage, '_loaded_data'):  # one last hack to make storage reload messages
            delattr(storage, '_loaded_data')
        res.messages = [dict(level=item.level, message=item.message) for item in storage]

Обратите внимание, что внутренне это все еще решение для опроса (цикл постоянно перезагружает сообщения), но это подтверждает концепцию и в конечном итоге - работает. Любая базовая оптимизация механизма хранения / обработки сигналов выходит за рамки этого ответа.

Другие вопросы по тегам