Reputation: 7450
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:
os.environ
internally to set the environment variable but to no effect.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.
Upvotes: 3
Views: 1564
Reputation: 7450
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:
deployment/
__init__.py
fabric/
__init__.py
database.py
repo.py
services.py
myproject/
app1/
app2/
appN/
manage.py
fabfile.py
Inside the deployment/fabric/database.py
I had this code:
django.settings_module('myproject.settings.devel')
@task
def syncdb():
local('python manage.py syncdb --noinput')
And inside my fabfile.py
I had all my imports:
from deployment.fabric.database import dropdb, createdb, syncdb, createuser
from deployment.fabric.something import blahblah
For some reason, that I can't seem to grasp right now, inside the fabfile.py
the 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.environ
actions do not persist
across 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 local
function and saw that it essentially is a wrapper
over subprocess.Popen('...', shell=True)
. So I tested my previous experiment
with subprocess.Popen
and 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 prefix
context manager
def syncdb():
with prefix('export DJANGO_SETTINGS_MODULE=myproject.settings.devel'):
local('python manage.py syncdb --noinput')
2) Append a --settings
value in the local
command (as described by hynekcer)
@task
def syncdb():
local('python manage.py syncdb --settings=myproject.settings.devel --noinput')
3) Include the settings_module
call inside the task(Although it kinda invalidates its purpose).
@task
def syncdb():
django.settings_module('myproject.settings.devel')
local('python manage.py syncdb --noinput')
Upvotes: 1
Reputation: 15548
You can use settings
option. It has precedence over DJANGO_SETTINGS_MODULE variable.
@task
def syncdb():
local('python manage.py syncdb --settings=myproject.settings.devel --noinput')
Upvotes: 1