Opened 14 years ago

Closed 12 years ago

#13894 closed Bug (wontfix)

Disable upstream caching with messages framework

Reported by: Torsten Bronger Owned by: nobody
Component: contrib.messages Version: 1.2
Severity: Normal Keywords:
Cc: bronger@… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Upstream caching should be disabled when messages have been consumed in the current request. I added

    if request._messages.used:
        add_never_cache_headers(response)

to "process_response" of MessageMiddleware and it works nicely for me. Doesn't it make sense to do that always, or at least, by default?

Rationale:

When the message framework is used and the messages are iterared over in the current view, this means that it is posible that they are displayed and consumed. Thus, when the same page is retrieved next time, they won't appear, or with different content.

It is very difficult to handle this in cache-related code of that view because the messages have been generated in a previous request, which may even belong to another view.

Change History (5)

comment:1 by Chris Beaven, 14 years ago

Component: UncategorizedContrib apps
Triage Stage: UnreviewedDesign decision needed

It does sound like a valid issue.

But isn't the opposite true as well? If a page (without any messages displayed) is cached, then assuming messages were in the queue and this page was hit again, the messages will not get rendered (or consumed). It seems like fixing this only fixes half of the caching problem.

comment:2 by Torsten Bronger, 14 years ago

First of all: As we had to find out, "add_never_cache_headers" doesn't work. It only sets "Expires" and "Cache-control/max-age" but it also sets "ETag" and "Last-Modified" so that the next request may be taken from the browser's cache. (It's strange that such a function is called "add_never_cache_headers". It should be called "add_expire_immediately_headers". Anyway.)

Instead, we use

if request._messages.used:
    del response["ETag"]
    del response["Last-Modified"]
    response["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
    # FixMe: One should check whether the following settings are
    # sensible.
    response["Pragma"] = "no-cache"
    response["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate, private"

Now to your question. You're absolutely right. We don't run into this problem because messages are shown on pages which have recently changed anyway (the message reads "You have successfully changed ..."). If we had a message saying "Editing aborted. Nothing was changed.", it would not get displayed.

comment:3 by Gabriel Hurley, 13 years ago

Component: Contrib appscontrib.messages

comment:4 by Graham King, 13 years ago

Severity: Normal
Type: Bug

comment:5 by Aymeric Augustin, 12 years ago

Easy pickings: unset
Resolution: wontfix
Status: newclosed
UI/UX: unset

I don't think Django can handle this problem automatically and correctly.

It is a very common pattern to loop over messages in the base template of a website. If we disable caching simply because messages might be displayed on a given page, we're just killing the cache for most websites. If we disable it only when messages are displayed, we're only resolving half of the problem, as explained in comments 1 and 2.

To sum up:

  • Caching dynamic pages is hard :)
  • Use ETags to save bandwidth — Django provides a lot of flexibility at this level.
  • Use fragment caching in templates to save CPU — but don't cache dynamic parts, like messages!
Note: See TracTickets for help on using tickets.
Back to Top