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 framework, что позволило бы мне опрашивать любые изменения сообщений и сообщать об этом браузеру, когда это происходит? Или другой метод, который достиг бы того же самого более элегантно?

1 ответ

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

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

    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]
    

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