I have the following scheme for my project’s settings:
myproject/
app1/
app2/
appN/
settings/
__init__.py
base.py
devel.py
production.py
In my local environment I have inside the virtualenvwrapper’s postactivate script:
myproject_root=/home/rantanplan/Projects/repos/myproject
cd $myproject_root
export DJANGO_SETTINGS_MODULE=myproject.settings.devel
So that when I do workon myproject it will change to the project’s root dir and
set the active DJANGO_SETTINGS_MODULE I want.
This is fine for django and all the commands(like python manage.py syncdb) work.
Now on the other hand I have this fabric task:
@task
def syncdb():
local('python manage.py syncdb --noinput')
This used to work fine when I had a simple settings.py file, but when I changed
to the above scheme it raises this exception:
django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.
Fatal error: local() encountered an error (return code 1) while executing 'python manage.py syncdb --noinput'
Aborting.
Some additional notes:
- project function is not applicable here since it falsely assumes(internally) that all django settings modules are named as “settings”.
- I tried the settings_module function to no avail. It uses
os.environinternally to set the environment variable but to no effect. - If I print the
os.environ['DJANGO_SETTINGS_MODULE']just before my task definition, it correctly prints “myproject.settings.devel”.
So what am I doing wrong here and how do you propose I should go about solving this issue?
To spare you the trouble I should say that I know I can solve this by doing:
def syncdb():
with prefix('export DJANGO_SETTINGS_MODULE=myproject.settings.devel'):
local('python manage.py syncdb --noinput')
but I’d rather avoid the use of prefix if I can.
Also I know I could do, as hynekcer suggests:
@task
def syncdb():
local('python manage.py syncdb --settings=myproject.settings.devel --noinput')
but I really want to know why local does not respect the DJANGO_SETTINGS_MODULE and
why settings_module does not work as advertised.
Well I found the problem but I’m not sure what to make of it.
First of all it seems that I didn’t reveal all the necessary bits of information.
Although my django project’s structure is exactly as I described, my fabric
structure is a bit more complex.
In essence I follow some patterns from this part of fabric’s documentation
The complete structure is described below:
Inside the
deployment/fabric/database.pyI had this code:And inside my
fabfile.pyI had all my imports:For some reason, that I can’t seem to grasp right now, inside the
fabfile.pythe setting of the
DJANGO_SETTINGS_MODULE(which was happening inside the deployment/fabric/database.py) is not retained.At first I came to the false realization that
os.environactions do not persistacross modules! But this is not true, as I immediately constructed a similar scenario
outside my django project and invalidated my false premise.
Then I checked fabric’s
localfunction and saw that it essentially is a wrapperover
subprocess.Popen('...', shell=True). So I tested my previous experimentwith
subprocess.Popenand it still retained the environment variables across modules.I don’t know if it has to do with fabric’s magic tasks import or there is something
fundamental I don’t grasp but any of the below methods will solve the issue.
1) Use the
prefixcontext manager2) Append a
--settingsvalue in thelocalcommand (as described by hynekcer)3) Include the
settings_modulecall inside the task(Although it kinda invalidates its purpose).