floatingpurr
floatingpurr

Reputation: 8599

Cron job does not load virtualenv env var for working with django.setup()

Well, I have a project structure like this one:

my_project
   |-scripts
   |  |- my_script.py
   |
   |-django_project
      |- myApp
      |  |- models.py
      |  |- ...
      |- django_project
         |- settings.py
         |- ...

I run Django inside a virtualenv and in my_script.py I have to use some of myApp.models

So, here is how I did:

my_script.py:

#!/usr/bin/env python
import django
django.setup()

from myApp.models import foo

# do things

Since I am inside a virtualenv, to make django.setup() work properly I set in my virtualenv ($VIRTUAL_ENV/bin/postactivate):

export DJANGO_SETTINGS_MODULE = django_project.settings

and I added django_project to the path:

$ workon my_virtualenv
$ python -c "import sys; print sys.path" 
['', '/my_project/django_project', ...]

And that's all.

If I activate my virtualenv and then I run my_script.py all works fine.

But If I schedule a similar cron job:

00 00 * * * /.../.virtualenvs/my_virtualenv/bin/python /.../my_project/scripts/my_script.py >> /.../test/test.log 2>&1

I get this error:

django.core.exceptions.ImproperlyConfigured: Requested setting LOGGING_CONFIG, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

It seems like my_virtualenv activation settings are not properly loaded.

Why does this happen, and how can I fix?

Upvotes: 0

Views: 943

Answers (3)

NDonelli
NDonelli

Reputation: 61

The problem is that cron is not an interactive shell and thus nor your .bash_profile nor your .bashrc are sourced by it.

Thus you do not source the script virtualenvwrapper.sh which is the one that defines the workon command and how hooks works.

To work around this fact you can define directly into the crontab the set of variables you need, that are

WORKON_HOME= the same as in your .bash_profile
PROJECT_HOME= the same as in your .bash_profile
VIRTUALENVWRAPPER_SCRIPT= the same as the value of the variable VIRTUALENVWRAPPER_SCRIPT in interactive shell (usually /usr/local/bin/virtualenvwrapper.sh)

and then add

source ${VIRTUALENVWRAPPER_SCRIPT}

at the beginning of all the scripts you are scheduling (if you want them to use virtualenvwrapper)

Upvotes: 0

thebjorn
thebjorn

Reputation: 27351

We use a small shell script to activate the virtualenv:

$ cat run-python.sh
#!/bin/bash

# put run-python.sh's directory on path (probably not needed, we call
# auxiliary scripts in the same directory)
myname="$0"
binprefix="$(dirname ${myname})"
export PATH=${binprefix}:${PATH}

VENV_DIR = '/path/to/venv/root'

# activate virtualenv
pushd ${VENV_DIR} > /dev/null
. bin/activate
popd > /dev/null

# set DJANGO_SETTINGS_MODULE
if [ "x$DJANGO_SETTINGS_MODULE" == "x" ]; then
  export DJANGO_SETTINGS_MODULE="default.settings"
else
  export DJANGO_SETTINGS_MODULE
fi

exec python $@

and use it in crontab like:

0/15 * * * *    DJANGO_SETTINGS_MODULE=myapp.settings run-python.sh /path/to/python/script.py

Upvotes: 1

Beomi
Beomi

Reputation: 1727

try with this on your python file:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings")
import django
django.setup()

and I suggest you to locate your my_scriptfile to your project root directory where the manage.pyfile is.

If not working, try like this:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.django_project.settings")
import django
django.setup()

Upvotes: 1

Related Questions