Closed philgyford closed 2 years ago
Hi,
The (2) /public*/
directories are there to hold your assets in a non-volume mounted location so they never get overwritten by your volumes. These get populated at build time when you build your Docker image, the /public_collected/
directory gets populated when collectstatic
gets run based on having set DEBUG=false
in your .env
at build time.
At runtime (thanks to https://github.com/nickjj/docker-django-example/blob/main/bin/docker-entrypoint-web) the public_collected/
directory gets copied over to /app/public_collected
where your volume can take over to allow you to persist files back to your Docker host and potentially serve these assets from a web server not running in Docker such as nginx.
It is pretty convoluted but I don't see a way around all of this. We have to meet 2 criteria here:
collectstatic
in the same directory where your source is, this means we need 2 sets of public/ directories, I named them accordinglyIf you have a way to meet both of these criteria in a cleaner way I'm all for improving it, keep in mind it would need to work in development too where assets aren't collected. I'd love to be able to get rid of this workflow.
Thanks that makes sense. I've only been using this for local development so far, so haven't quite grasped the differences with how it would work in production.
Previously I've only used manage.py runserver
during development, not gunicorn, and added "whitenoise.runserver_nostatic"
to INSTALLED_APPS
if DEBUG=True
. Which I think means I don't need to run collectstatic
except on the production server (where I wasn't using Docker).
I assume we need to run collectstatic
in development because we're using gunicorn?
Now that I'm thinking of using Docker for both dev and production I have this extra level of complication to get my head round I guess!
In my dabblings with Docker and Django I'm always frustrated that dealing with static files ends up being so complicated!
You don't need to run collectstatic
in development.
The exact instructions in the readme file combined with the source code in this repo will work out of the box and your assets will get served in development.
The collection process is mainly around digesting the files with an md5 hash, it's aimed at production although there's nothing stopping you from digesting them manually in development. It happens in production by default due to the Dockerfile having a condition to run it when DEBUG=false
:
Sorry, I'd just now realised collectstatic
is not run in development and was coming here to correct myself. Apologies; it's hard to follow exactly what's going on.
Found this issue because I was wondering the same @nickjj
We need to build both sets of public files in a non-volume mounted directory but also make them available in a volume at runtime in such a way where existing files in the volume on the Docker host at runtime won't overwrite the newly built public files, this means we need to store both sets of public/ directories in 2 locations
Why is this the case? Why not just build static assets into /app/public (binded to assets/public on the host) for development, and serve from this folder in development? And into /app/public_collected for production?
I don't understand the overwriting files issue, can you please explain a little more? Are you saying because you don't want your production build assets to overwrite the dev build assets? If so, why does it matter? I would imagine that's only an issue if trying to test your production flow locally, but in that scenario does it really matter if we overwrite the files when they can just be recompiled/generated again? And in the case where the prod build is happening on a different machine for deployments you won't have dev files there to overwrite anyway. Let me know if I'm missing something. Thanks.
@nullbio You quoted one of my bullets but the first bullet is:
Django does not let you output collectstatic in the same directory where your source is, this means we need 2 sets of public/ directories, I named them accordingly
We can't collectstatic in public/
because Django prevents this. Now, that was 2 years ago and I'm not sure if anything changed since then but back then if assets got built into public/
then collectstatic couldn't output its files in public/
, instead you had to use a separate directory and that's why I chose public_collected/
.
After building this, and running
./run manage collectstatic
I've noticed there are four directories for static assets in the web container (in addition to/app/assets
), but only two are used:/public
- always empty/public_collected
- fills with the assets aftercollectstatic
/app/public
- the static assetscollectstatic
collects/app/public_collected
- always emptyI wonder if this means there are some unnecessary creations in the Dockerfile, but I'm not sure which you intended to be correct? Or have I misunderstood something?