0

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?

floatingpurr
  • 5,024
  • 5
  • 30
  • 79
  • Remove your django.setup() call. If you're using/setting the DJANGO_SETTINGS_MODULE it should find all your settings there. – thebjorn Apr 01 '17 at 13:09
  • @thebjorn according to the Django Docs you have both to fix the env variable and to call django.setup(). I tried your hint but it did not work – floatingpurr Apr 01 '17 at 13:19

3 Answers3

1

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()
Beomi
  • 1,292
  • 13
  • 15
  • +1 'cause first solution worked fine. But I still do not understand why my env var is not set by cron when job is started. I guess that probably there is not a real activation event of the virtual env. – floatingpurr Apr 01 '17 at 13:24
1

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
thebjorn
  • 22,303
  • 7
  • 72
  • 116
  • Yep, good idea! Any idea on the reason why standard hooks are not triggered via cron? – floatingpurr Apr 01 '17 at 15:32
  • 1
    probably because cron doesn't have "any" environment. You need to explicitly set up anything you're going to use. Also, since you're not running `activate` I'm guessing any post-activate scripts aren't ran either (just calling the `python` executable in the virtualenv will do most things right when you get into Python, and will work great in many cases though) – thebjorn Apr 01 '17 at 15:37
0

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)

NDonelli
  • 51
  • 6