Here's the scenario:
I'm running Django 1.3.1, utilizing staticfiles, and django-compressor (latest stable) to, among other things, compile LESS files.
I have an "assets" directory that's hooked into staticfiles with STATICFILES_DIRS (for project-wide static resources). In that directory I have a "css" directory and in that a "lib.less" file that contains LESS variables and mixins.
So the physical path is <project_root>/assets/css/lib.less and it's served at /static/css/lib.less.
In one of my apps' static directory, I have another LESS file that needs to import the one above. The physical path for that is <project_root>/myapp/static/myapp/css/file.less and it would be served at /static/myapp/css/file.less.
My first thought was:
#import "../../css/lib.less"
(i.e. based on the URL, go up to levels from /static/myapp/css to /static/, then traverse down into /static/css/lib.less).
However, that doesn't work, and I've tried just about every combination of URLs and physical paths I can think of and all of them give me FilterErrors in the template, resulting from not being able to find the file to import.
Anyone have any ideas what the actual import path should be?
After tracking down exactly where the error was coming from in the django-compressor source. It turns out to be directly passed from the shell. Which clued me into removing all the variables and literally just trying to get the lessc compiler to parse the file.
Turns out it wants a relative path from the source file to the file to be imported in terms of the physical filesystem path. So I had to back all the way out to my <project_root> and then reference assets/css/lib.less from there. The actual import that finally worked was:
#import "../../../../assets/css/lib.less"
What's very odd though is that lessc would not accept an absolute filesystem path (i.e. /path/to/project/assets/css/lib.less). I'm not sure why.
UPDATE (02/08/2012)
Had a complete "DUH" moment when I finally pushed my code to my staging environment and ran collectstatic. The #import path I was using worked fine in development because that was the physical path to the file then, but once collectstatic has done it's thing, everything is moved around and relative to <project_root>/static/.
I toyed with the idea of using symbolic links to try to match up the pre and post-collectstatic #import paths, but I decided that that was far too complicated and fragile in the long run.
SO... I broke down and moved all the LESS files together under <project_root>/assets/css/, and rationalized moving the LESS files out of the apps because since they're tied to a project-level file in order to function, they're inherently project-level themselves.
I'm sort of in the same bind and this is what I've come up with for the most recent versions of compressor and lessc to integrate with staticfiles. Hopefully this will help some other people out
As far as I can tell from experimenting, lessc doesn't have a notion of absolute or relative paths. Rather, it seems to maintain a search path, which includes the current directory, the containing directory of the less file, and whatever you pass to it via --include-path
so in my configuration for compressor I put
COMPRESS_PRECOMPILERS = (
('text/less', 'lessc --include-path=%s {infile} {outfile}' % STATIC_ROOT),
)
Say, after running collectstatic I have bootstrap living at
STATIC_ROOT/bootstrap/3.2.0/bootstrap.css.
Then from any less file, I can now write
#import (less, reference) "/bootstrap/3.2.0/bootstrap.css"
which allows me to use the bootstrap classes as less mixins in any of my less files!
Every time I update a less file, I have to run collectstatic to aggregate them in a local directory so that compressor can give less the right source files to work on. Otherwise, compressor handles everything smoothly. You can also use collectstatic -l to symlink, which means you only need to collect the files when you add a new one.
I'm considering implementing a management command to smooth out the development process that either subclasses runserver to call collectstatic each time the server is reloaded, or uses django.utils.autoreload directly to call collectstatic when things are updated.
Edit (2014/12/01): My approach as outlined above requires a local static root. I was using remote storage with offline compression in my production environment, so deployment requires a couple extra steps. In addition to calling collectstatic to sync the static files to the remote storage, I call collectstatic with different django config file that uses local storage. After I have collected the files locally, I can call 'compress', having configured it to upload the result files to remote storage, but look in local storage for source files.
Related
I need a bit of clarification regarding how Django updates its static files. Here is a hypothetical that will explain my predicament:
I'm working on my own website which requires a link to a PDF that is stored as a static file.
Later I replaced this PDF file, with a slightly altered name, and made corrections respectively in my code.
Then I run the collectstatic command to replace the old static files and everything works as expected. Explorer shows me that the old files have been properly replaced in their respective folders.
When I go to test the link I'm still forwarded to my old PDF file. The old staticfile as if nothing has been replaced.
Can anyone explain to me how this happened? I'm just concerned and a bit freaked out that my old static file is still being referenced. I mean it could just be a simple typo or I have a haunted static folder on my hands.
When collectstatic command is run Django searches for present static files in STATICFILES_DIRS and copies them into STATIC_ROOT path.
The link to file that Django returns - is exactly how it is set in code - Django will not search it this file is present to show the link.
Check or search your code for old file name, maybe it is left somewhere.
Also, static files usually are css, js, images - files used in rendering page. User content, data files (PDF file looks to be one of these) for downloading via download link - should be served as MEDIA FILES.
with io.open("filepath/filename",mode="w",encoding="utf8") as file:
file.write(jsondata)
But it seems something wrong.
my flaskapp return 500 and no error logs
But when i remove it everything can run as normal.
what should i do?
If you are using OpenShift 2, it is likely your web application is running under Apache/mod_wsgi. You shouldn't in that case be using relative path names as the current working directory of the application is effectively undefined and likely not writable. Instead construct an absolute path name. Depending on what file is for, you may be best to write files into the data directory provided to you and specified by the OPENSHIFT_DATA_DIR environment variable, if it potentially needs to persist. Or OPENSHIFT_TMP_DIR if a temporary file. Details of important variables for directories can be found in:
https://developers.openshift.com/managing-your-applications/environment-variables.html#directory-variables
As to why you aren't seeing any error, this is likely because Flask is swallowing the error up when generating the 500 response. You would need to configure Flask to log details of the error.
After a long time away from an app i wrote in Django and didn't complete, I've come back to it on a new Mac.
I'm struggling to get the code to refer to the apps and the files within them without the explicit path. For instance:
from myproject.app.file import object
Whereas I remember not having to use myproject every time.
Is this something that has changed? I seem to remember being about to add to the path in manage.py which is called every time you run the dev server, but this hasn't worked this time.
sys.path.append /path/to/myproject
Should that fix the issue I'm having?
I started with a simple answer and it grew into more details on how to add subdirectories of your project to python path. Maybe a bit off-topic, but it could be useful to you so I'm pushing the post button anyway.
I usually have a bunch of small re-usable apps of mine I keep inside my project tree, because I don't want them to grow into independent modules. My projet tree will look like this:
manage.py
myproject/apps
myproject/libs
myproject/settings
...
Still, by default, Django only adds the project root to python path. Yet it makes no sense in my opinion to have apps load modules with full path:
from myproject.apps.author.models import Author
from myproject.libs.rest_filters import filters
That's both way too verbose, and it breaks reusability as I only use absolute imports. Not to mention if I someday build an actual python package out of some of the libs, it will break.
So, I took the following steps. I added the relevant folders to the path:
# in manage.py
root = os.path.dirname(__file__)
sys.path.append(os.path.realpath(os.path.join(root, 'myproject', 'apps')))
sys.path.append(os.path.realpath(os.path.join(root, 'myproject', 'libs')))
But you must ensure those packages cannot be loaded from the root of the project, or you will have odd issues as python would load another copy of the module. For instance, isinstance(libs.foo.bar(), myproject.libs.foo.bar) == False
It's not hard though : just remove __init__.py from the folders you add to the path. That will make sure they cannot be descended into from the project.
Also, Django's discover runner will not descend into those paths unless you specify them manually. That may be fine with you (if every module has its own test suite). Or you can extend the runner, so it knows about this: sample code.
I am severely confused about where to put my templates files and static files.
I understand absolute and relative paths just fine, but I can't seem to find any instructions that mirror the installation I have. I know this resembles other questions, but those answers aren't working. The video I watched to successfully build a simple app didn't put templates in the Project folder, which is where logic tells me they should be.
I have Python at:
C:\Python27
Django (v1.6.5) at:
C:\Python27\Lib\site-packages\django
I created a project "mysite" and an app called "films."
Project "mysite":
C:\Python27\Scripts\venv\mysite
and an App "films":
C:\Python27\Scripts\venv\mysite\films
The video I watched had me put my templates at:
C:\Python27\Lib\site-packages\django\contrib\admin\templates
But this seems completely stupid because the templates are outside of both the Project and the App.
Shouldn't I put a templates folder in the Project folder:
C:\Python27\Scripts\venv\mysite\templates
And then create subdirectories using the App name?
What files do I need to edit (and how) to tell Django where to find them?
Follow a similar process for static files (css, images)?
Like all frameworks, django offers great benefits if you follow some guidelines (and give up some control). The trick is to know what these guidelines are.
For templates:
If the template is not tied to a particular application, put it in a templates directory at the root of your project. Add the full path to this directory to TEMPLATE_DIRS.
All other templates should go in a directory called templates inside your application directory. So if you application is called myapp, templates for myapp will go in myapp/templates/
For static files:
For files related to specific applications, inside your application directory create a directory called static, then inside it a directory with the name of your application. So, if your application is called myapp, you would have myapp/static/myapp. Place all your static content for this application here; for example myapp/static/myapp/js/funky.js.
For static files that are generic, create a directory called assets (or static) in the root directory of your project. Add the full path to this directory to STATICFILES_DIRS.
By default, django will search all applications listed in INSTALLED_APPS, and add any templates and static directories to its search path for files. This is how, by default, the admin works without you having to configure anything.
If you chose to place your templates and static files in some other location, only then do you need to modify the TEMPLATE_DIRS and STATICFILES_DIRS settings. If all your templates and static assets are tied to applications, just creating the directories as mentioned above makes everything work.
If you are wondering why you need to create another directory under myapp/static/ to store your static files, this is more for portability. The collectstatic command is a simply "copy and replace" utility. It will overwrite all files in the STATIC_DIR location. This means that if two applications have some static file with the same name, they will be overwritten without warning. Adding a subdirectory keeps your application's static assets from being overwritten, because the exact path will be created.
Suppose you have two applications, app1 and app2, and both have a file named style.css in their respected directories:
app1/static/css/style.css
app2/static/css/style.css
When you run collectstatic, you'll end up with the following (assuming static is the name of your STATIC_DIR setting):
static/css/style.css
This may be the style.css from app1 or app2, the other cannot be determined (its actually based on the INSTALLED_APPS order). To prevent this, if you have:
app1/static/app1/css/style.css
app2/static/app2/css/style.css
Now, you'll end up with:
static/app1/css/style.css
static/app2/css/style.css
Both files will be preserved.
You also shouldn't put your code in your virtual environment directory. The virtual environment is not part of your source code, and placing your project in the same directory may cause problems later.
Create a single directory for your environments - I call mine envs (creative, I know). Create all your environments in this directory. Once you activate the environment, you can work in any directory in your system and your shell will be configured for that environment's Python.
Finally for the best, accurate, most up-to-date information - always refer to the django manual and the tutorial. Almost all other resources (even the often suggested djangobook.com) are outdated.
I have a problem with my app here. My configuration is as such I can upload a new release and symbolically link it for production -- however, this means every time I upload a new release, all of the photos that were uploaded in any parts of my entire project are wrapped into the old release and disappear.
How can I save these files to a static file location which does not get wrapped in the release? Thanks in advance.
I guess best for this is keeping your media files out of your source project folder, you could eg have a structure like:
myproject
|
|----media
|----src
There's no need to have the media folder in the same directory as your source code, apps etc. So you have a solution where the dir with your release only contains static files! The same applies to the database, if you are using sqlite... Have a look at this for a more detailled structure!
Of course this no must, but experience shows it makes live much easier!