Managing static files for multiple apps in Django - django

I am developing a Django (1.3) project composed of many applications. Each application has its own static files under its own static directory. Moreover, I have added a directory called project_static which should contain static files which are common throughout the various applications, such as jQuery.
The problem I immediately run into is that of naming collisions. By default, collectstatic will just put everything under a global static directory, without classifying them by application. This does not work for me, as each application has - for instance - a file called css/screen.css.
The way I solved it is by removing django.contrib.staticfiles.finders.AppDirectoriesFinder from STATICFILES_FINDERS and using namespaced static files dirs, so my settings now look like:
STATICFILES_DIRS = (
os.path.join(PROJECT_PATH, 'project_static'),
('my_app', os.path.join(PROJECT_PATH, 'my_app', 'static')),
('another_app', os.path.join(PROJECT_PATH, 'another_app', 'static')),
...
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
)
The problem is that in this way I lose the static files for all other applications (e.g. django.contrib.admin). Of course I could manually add the admin, but I'm not sure how to do this without breaking the admin, which has a different directory structure.
Is there a better way to manage the static files with more than one application?

This is the same problem that occurs with using app-specific templates directories. If you just throw the files directly under templates in the app, you'll end up with name collisions if two apps or even the project-level templates directory utilize templates of the same name. The fix for that is to actually put the templates in a directory of the name of app inside the templates directory like:
- some_app
- templates
- some_app
- index.html
So, I apply the same idea to static:
- some_app
- static
- some_app
- css
- img
- js
That way, when you run collectstatic, each individual app's static files get placed inside a namespaced directory. The only change you need to make is to prefix each of the files with the app-name directory in your templates. So instead of {{ STATIC_URL }}css/style.css you have {{ STATIC_URL }}my_app/css/style.css.

Related

Using both the project level and the app level static files in django

I have some static files that will remain common through all the application and I also have some static files that are specific to some particular apps only. Now in one of my apps, i want to use both the project level and the app level static files but that doesn't seem to work.
Following code section is from settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "homepage","static"),
os.path.join(BASE_DIR, "landing_page","static"),
os.path.join(BASE_DIR, "static"),
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
I have used python manage.py collectstatic
and it returns with a warning which goes like Found another file with the destination path 'homepage\css\style.css'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure
every static file has a unique path.
Despite the above warning, I still get both the project level and the app level static files in the staticfiles folder in my root directory. When I use it in a template, the project level static file gets loaded while the app level static file (which is just a single CSS file) doesn't get loaded. Following is how I am trying to load the CSS file.
{% load static %}
<link rel="stylesheet" type="{% static 'homepage/css/style.css' %}" href="PATHTOCSSHERE">
The developer tool of chrome also doesn't show the app level CSS file in the list of loaded files, which clearly means that the file doesn't get loaded.
You need to follow the template principle of putting your app-specific files inside another level of directory with the app name - for example /project/homepage/static/homepage/css.... Now your links will work (with your existing settings).
However unless you are actually distributing your apps independently, I don't find this a helpful way of organising things. Just use your project-level static directory, and have app-specific directories in there - /project/static/homepage/css.... Then you just need a single directory in STATICFILES_DIRS.
I am absolutely sorry everyone. Just saw an obvious mistake in my own code. The error has been resolved now. Thanks!

recommended location for static & templates directories

I am a little bit confused about the recommended location of the templates and static directories. Apparently it is better to have 1 templates directory in every app folder. Django automatically look for templates there. However it seems not to be the case for static, is it? Can I tell django to look for static within the directory of the app currently running (instead of a single directory in the root folder)?
Thanks.
you can manually setting django to look where static files are.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"), # basic, noqa.
os.path.join(BASE_DIR, "blog/other_static"), # another static folder in blog app
)
Django will look those folders.
and one more, you may set your static folder like static/blog/js/some.js and static/otherapp/css/some_css.css.
You may make folder in static directory named same as your app.
And I'm not suggest managing your static files in your app directory unless you're going to use your app as reusable.

Order of finding static files and templates in django-apps

For example I have 2 apps in my django project with templates and static files with identical subpath:
app1 /
static /
style.css
templates /
index.html
app2 /
static /
style.css
templates /
index.html
than, in settings.py I added this two apps:
INSTALLED_APPS = (
'app1',
'app2',
)
now I use in some way 'style.css' and 'index.html' in templates, e.g.
{% include 'index.html' %}
so, question is:
Does Django guarantee that when I reference to 'style.css' or 'index.html' will be used files from app2 subdirectories?
Is it any other way to point Django preferable variants of files in such situation?
As per documentation, first match wins:
Duplicate file names are by default resolved in a similar way to how
template resolution works: the file that is first found in one of the
specified locations will be used.
https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#django-admin-collectstatic
Now, when you tell Django to collect static files or render templates, Django asks special "finders" in order they are defined in your configuraiton for specified resource.
Default order for static files is "FileSystemFinder" that searches STATICFILES_DIRS in order they are added in it. If FileSystemFinder fails to find file in those dirs, Django uses next finder set, the "AppDirectoriesFinder" that searches in "static" subdirectories in your apps directories.
Same mechanic is applied to templates. When you tell Django to render "index.html", it first asks "filesystem.Loader" find template named like that in directories defined in TEMPLATE_DIRS. If search fails, Django asks next template loader, "app_directories.Loader" that searches template dirs in applications "templates" subdirs.
To answer your question, because app1 is registered before app2, Django will use it's style.css and index.html instead of ones coming from app2. If you want to change this behaviour, put app2 above app1 in your installed apps setting.
Documentation:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.app_directories.Loader

Static file cannot be found in Django view

I am having an issue with static files in the development server on Django 1.5.4. I am not sure if it is the same problem on the actual production server (running Apache), as I found a solution for that which works at the moment (simply hard coding the full URL - I know it's bad, but it gets the job done).
I am using Reportlab to create a PDF file for my project, and I need to include a picture on that. I followed the answer in a different post:
from django.templatetags.static import static
url = static('x.jpg')
Unfortunately, the answer I get from the server is an IO Error: 'Cannot open resource "localhost:8000/static/images/x.jpg"', even though a copy and paste of that into the URL bar clearly shows me that the picture is exactly there.
My settings regarding static files are the following, and they do work for everything else (CSS, Javascript, etc):
ROOT_PROJECT = os.path.join(os.path.split(__file__)[0], "..")
STATIC_ROOT = os.path.join(ROOT_PROJECT, 'static')
STATICFILES_DIRS = ()
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
Thanks for your help!
Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS.
There are usually a couple of ways to store static files.
One way is to create a static folder inside your app folder and store the files there. You can check that here:
Is to create a folder and store your static files which are not for any particular app.
From the django documentation:
Your project will probably also have static assets that aren’t tied to a particular app. In addition to using a static/ directory inside your apps, you can define a list of directories (STATICFILES_DIRS) in your settings file where Django will also look for static files.
For example:
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
'/var/www/static/',
)
If you are into production then check production deployment for more details!

Django and staticfiles questions

The more I learn Django, the more I discover new things.
I read the official docs, stackoverflow and google but I still have doubts.
What's the correct/normal way to organize our static files?
I mean folders and settings.py
I have something like:
CURRENT_PATH = os.path.dirname(__file__)
STATIC_ROOT = os.path.join(CURRENT_PATH, 'static')
STATIC_URL = '/static/'
Ok, Im going to collect all my apps statics on ~/static/
I created a static/appname folder on every app and I put all my app's static there.
Also, I need a static folder to project-wide statics (what's the common name for it? Since I used /static/ for collected stuff and they cannot be equal).
So far so good, I have css like:
href="{{ STATIC_URL }}appname/styles.css"
and it works like charm.
But I think that when I deploy my app, I have to run 'collectstatic' so I put that '/static/' folder serving on Cherokee.
The question is... will that work? I tried commenting the AppDirectoryFinder and the _DIRS one and that doesn't work on local (Having the static stuff collected, I mean, the css on /static/ and in the other folders too).
Is just better to have one static folder on root for all the project? And copy the admin css to that folder (AKA manually collectstatic).
The projects I see on github/bitbucket are ready to be deployed, I need to know the steps to go from dev to deploy.
Thanks!
I'll break this down as I use the django static app
url at which your static media will be served
STATIC_URL = '/static/'
this is used for 2 things
{{STATIC_URL}} in your templates and the static file url
and for hosting your static files in django (DEVELOPMENT ONLY)
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
The location at which your files reside on the server
STATIC_ROOT = '/var/www/website/static'
this is used when you run collectstatic and is where your webserver should be looking
your file finder definition
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
I've used the default from django you can of course use more but here is the crux of what you are looking to know
'django.contrib.staticfiles.finders.AppDirectoriesFinder'
will find any folder named "static" that is inside an installed app
'django.contrib.staticfiles.finders.FileSystemFinder'
will tell django to look at STATICFILES_DIRS (this is your project wide static files)
which should be defined as a tuple
STATICFILES_DIRS = (
join( CURRENT_PATH, 'static' ),
)
where 'static' is whatever you want and you can add in as many other folders to monitor as you wish.
the sub directories you place inside each app ie:app/static/appname are not necessary but will ensure that files of the same name inside different apps don't overwrite files from other apps or your root static folders
all of this was taken from my own experience and https://docs.djangoproject.com/en/1.3/ref/contrib/staticfiles/
Also, I need a static folder to project-wide statics (what's the common name for it? Since I used /static/ for collected stuff and they cannot be equal).
Are you sure? I'm pretty sure I'm using the same folder to collect my static files and to hold my project-wide static files. Not sure if that's not recommended pracice, but it works for me.
Note that this is just on the deployment side; my codebase just has the project static files.