Django:从存储中删除重复的消息

roc*_*ier 2 django django-middleware django-messages

我正在使用messages向模板添加flash消息(正如您所期望的那样).

我遇到的问题是,如果您双击指向生成消息的页面的链接,则该消息将出现两次.

我正在使用该消息告诉用户我已将它们重定向到他们期望的位置.他们不需要两次相同的消息.

我理解这里的逻辑,但我想知道如何删除重复的消息.

  • 点击网址
  • 消息生成,保存在存储中
  • 页面渲染之前再次单击URL
  • 生成第二条消息,保存在存储中
  • 响应添加来自存储的所有消息
  • 渲染两条消息

最终我希望这是一个middleware可以覆盖所有请求.

qur*_*ur2 6

Ran into the same problem and found another solution, using a custom MESSAGE_STORAGE:

from django.contrib.messages.storage.session import SessionStorage
from django.contrib.messages.storage.base import Message


class DedupMessageMixin(object):
    def __iter__(self):
        msgset = [tuple(m.__dict__.items())
                  for m in super(DedupMessageMixin, self).__iter__()]
        return iter([Message(**dict(m)) for m in set(msgset)])


class SessionDedupStorage(DedupMessageMixin, SessionStorage):
    pass


# in settings
MESSAGE_STORAGE = 'some.where.SessionDedupStorage'
Run Code Online (Sandbox Code Playgroud)

This will work fine with code that would also play with messages directly, say in a view for example. Since it's a mixin, you can easily reuse it for other message storages.

Here is an alternative to avoid storing duplicates at all:

from django.contrib.messages.storage.session import SessionStorage
from itertools import chain


class DedupMessageMixin(object):
    def add(self, level, message, extra_tags):
        messages = chain(self._loaded_messages, self._queued_messages)
        for m in messages:
            if m.message == message:
                return
        return super(DedupMessageMixin, self).add(level, message, extra_tags)
Run Code Online (Sandbox Code Playgroud)


Pau*_*ipp 6

我在中间件中遇到了同样的问题,但我更喜欢使用我正在使用的信息调用的一个小包装器:

from django.contrib.messages import info
from django.contrib.messages import get_messages


def info_once_only(request, msg):
    """
    Just add the message once
    :param request:
    :param msg:
    :return:
    """
    if msg not in [m.message for m in get_messages(request)]:
        info(request, msg)


class PaymentsMiddleware(object):

    @staticmethod
    def process_request(request):
        """
        Put up a message letting a new user know that they are being dealt with.
        :param request:
        :return:
        """
        if hasattr(request, 'user'):
            user_profile = request.user.get_profile()
            if user_profile and user_profile.is_suspended:
                info_once_only(
                    request,
                    "Hi {username}, your account has been suspended, we'll be in touch shortly.".format(                           
                        username=request.user.username))
    return None
Run Code Online (Sandbox Code Playgroud)