#python #django #django-messages
#python #django #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 ничего не делает, потому что платформа messages просто перечитывает переменную сеанса, которая «обновляется» только при новых запросах.
Я попытался заглянуть в базовый код, чтобы узнать, есть ли что-нибудь об обновлении хранилища на лету, но, похоже, нет кода, который бы это делал, по крайней мере, в среде обмена сообщениями. Был этот многообещающий недокументированный storage.update()
метод, но оказалось, что он делает что-то еще.
Итак, есть ли что-нибудь в Django framework, что позволило бы мне опрашивать любые изменения сообщений и сообщать об этом браузеру, когда это произойдет? Или другой метод, который позволил бы добиться того же более элегантно?
Ответ №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]
Пожалуйста, обратите внимание, что внутренне это все еще решение для опроса (цикл постоянно перезагружает сообщения), но оно подтверждает концепцию и, в конечном счете, работает. Любые базовые оптимизации механизма хранения / передачи сигналов выходят за рамки этого ответа.