Currently, when Django serves static files in development it doesn’t include any cache headers, which allows the client to decide for itself whether or not, and for how long, to cache the resource. Instead, Django should serve these files with a Cache-Control: no-cache header to prevent caching.
This issue has been raised in several tickets (27572, 32891, 33148), and is marked as wontfix because, in brief, “We want to see the caching correctly set”.
The problem is that we don’t know how to correctly set the caching. Since Django doesn’t serve static files in production, that information exists somewhere else (an Apache configuration file, for example). Any given file could be designed to be cached forever, or never, or anything in between.
Given that, the only reasonable approach is to instruct the client not to cache files. Caching is an optional feature of HTTP, and not caching just means the server is receiving the requests it was designed to receive. Not caching can’t break your website, but caching files that were not meant to be cached definitely can.
Even if you think that static files should be cached by default in development, leaving off cache headers is the worst way to accomplish that. That allows the client to cache the files for an indeterminate and unreproducible amount of time, which is not what you want in a development environment.
(The tickets above are mostly focused on the issue of developer convenience. I think that’s another good reason not to cache - and presumably that’s why whitenoise disables caching in development even though it actually does know what the correct values should be - but the more important concern is the correctness issue.)
So, I actively do want the current behaviour. It’s me you’ve quoted there.
I’m not at all worried by the lengths of time argument, and all that jazz. Rather I want (and need) to see the behaviour with the browser fetching the assets from cache, which is the usual behaviour I need to see.
Often I want to turn that off. No problem, all the browsers have a quick access toggle to disable it.
Often I’m developing against an embedded web view in a mobile application. No problem, my browser makes the dev tools instantly available for all running web views, on all my development devices.
In neither of these latter cases does it merit setting up a web server in order to be able to observe the first, which is by far the most frequent case, and has no equivalent UI switch to turn it on, if were to be off by default.
This is why I’ve argued to maintain the current default, which is correct in my opinion. I hope that makes sense.
If you “need to see the behavior with the browser fetching assets from the cache” then you don’t want to leave off cache headers. That allows the client to do whatever it wants, including not caching anything at all.
The good news is that if you really do desire this behavior you can get it easily enough, no second server required. Just use the same monkeypatch that you’ve pointed out to others to change the cache header.
You didn’t address my point about correctness so let me expand on that. When the server uses no-cache the client is required by the standard to respect that. Sites can and do rely on that for their correct behavior. Imagine a site with an index.html and app.js, both of which are meant to be served with no-cache to ensure that they’re always in sync. Now the Django development server comes along and, in effect, strips the no-cache header, allowing the two resources to get out of sync. That could break the site, in arbitrarily bad ways.
The reverse isn’t true. A site that enables caching can’t be broken by the addition of no-cache, since caching is an optional part of HTTP and the server has to be ready to serve a fresh resource at any time.
When working production code is broken by the development server we should consider that a bug. Fortunately this is very easy to fix, and would bring Django’s behavior in line with whitenoise.
Sorry, I’m not seeing how you get to Django stripping the no-cache header? If you set a header it’ll be part of the response.
The current behaviour isn’t incorrect. It’s just not what you’d prefer as far as I can see.
All your suggestion amounts to then is flipping the current default. Except I don’t think browsers have a UI button to enable caching even though there’s a specific header saying not to, so it would be strictly less flexible.
Unless there’s a new consideration I’m still against a change here.
The approach on the tickets seems pretty lightweight if you really don’t want the current behaviour.
I can’t find it instantly now but there was a ticket (or a discussion) about making static files serve better integrated into the middleware chain, rather than sitting beside it. I’m guessing maybe that’s the root of your complaint. It might be feasible to push on resolving that. (As a Saturday thought…)
But the header will never be set, that’s the point I think you’re missing. The correct header values are not available to Django, they’re off in an Apache configuration file, or an S3 setting, or some such. I’m not sure what ticket you’re talking about, but using the middleware stack won’t make any difference because the correct values are simply not in Django.
Imagine a static file in S3 configured to send a no-cache header. Clients are required to obey that header, and the site can depend on that for its correct behavior. In development, though, Django serves that file without a cache header, allowing the client to cache it, changing the behavior of the program. Sure, the development server didn’t take a response and literally strip off the header (that’s why I said “in effect”), but the outcome is the same. A program that’s completely correct and works in production can be broken when served in development because of the missing header.
If Django was able to serve static files with the production cache headers then this would indeed be a question of developer preference. But it can’t, in which case the only cache header guaranteed to preserve the behavior of the program is no-cache.
I think fundamentally we need to discuss who the users are of the software and what they want to do. I would argue the users are developers, and that they want to change their app, and after having changed their app, they want to use the app with the changes.
I am very active on the Unofficial Django Discord and every time anyone new asks anything at all about static files, you can pretty much blindly say “install whitenoise” and solve the problem. This isn’t a great situation…
I agree with the OP. It would be better if static files are not cached. Less flexible, but it is what you want in development 99 % of times. This could be configurable, but if the question is what the default should be, than no caching.
I, OTOH, am developing an application where a big part of the application is running inside the browser (~1k JS/TS files). So my dev environment is basically useless if it weren’t able to run the code I’m editing in the browser after a plain reload. Not using no-cache in my case would be similar to using ./manage.py runserver --noreload in your case.
I categorize not doing one of the following as a usability problem:
Disable caching while DEBUG is true.
Provide a setting to disable caching without installing additional dependencies or monkey-patching Django internals.