[Fixed]-How to call django.setup() in console_script?

1👍

Since I love condition-less code, I use this solution. It’s like in the django docs, but the ulgy if __name__ == '__pain__' gets avoided.

File with code:

# utils/do_good_stuff.py
# This file contains the code
# No `django.setup()` needed
# This code can be used by web apps and console scripts.

from otherlib import othermethod

def say_thank_you():
    ...

File for main:

# do_good_stuff_main.py
import django
django.setup()

def say_thank_you_main():
    from myapp import do_good_stuff
    return do_good_stuff()

setup.py:

    'console_scripts': [
        'say_thank_you=myapp.do_good_stuff_main:say_thank_you_main',
    ...

This is my current solution. Ffeeback welcome. Is there something to improve?

8👍

had the same problem (or something similar). I solved it by doing:

[Warning: dirty solution]

if not hasattr(django, 'apps'):
    django.setup()

this way it’ll be called only once even if it’s imported multiple times

7👍

Here https://docs.djangoproject.com/en/1.10/_modules/django/#setup we can see what django.setup actually does.

Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry.
Set the thread-local urlresolvers script prefix if set_prefix is True.

So basically to ensure that setup was already done we can check if apps are ready and settings are configured

from django.apps import apps
from django.conf import settings

if not apps.ready and not settings.configured:
    django.setup()

2👍

I have worked in two production CLI python packages with explicitly calling django.setup() in console_scripts.

The most important thing you should note is DJANGO_SETTINGS_MODULE in env path.

You can set this value in shell script or even load default settings in your python script.

Here is example:

# setup.py
entry_points={
    'my-cli = mypackage.cli:main'
}

.

# cli.py
import logging
from os import environ as env


if not 'DJANGO_SETTINGS_MODULE' in env:
    from mypackage import settings
    env.setdefault('DJANGO_SETTINGS_MODULE', settings.__name__)


import django
django.setup()

# this line must be after django.setup() for logging configure
logger = logging.getLogger('mypackage')

def main():
    # to get configured settings
    from django.conf import settings

    # do stuffs


if __name__ == '__main__':
    main()
👤dinhnv

0👍

In Django 2.2.5 (at least), the settings are configured on their import. django.setup() configures them because it imports them. The problem with calling django.setup() twice is that you’d be populating the apps specified in settings.INSTALLED_APPS twice which can cause all sorts of problems.

The if not apps.ready: check is all you should use thus:

import django

if not apps.ready:
    django.setup()

Using if not (apps.ready or settings.configured): – is wrong because the settings may have been configured with an import statement elsewhere and the apps might still not have been populated so django.setup() might not get called when it is needed.

That said, if you know your standalone entry point (e.g. main.py) you can just call it there without the condition. The condition is only needed if there is a risk of actually running the script twice, perhaps by importing your standalone module into another standalone module so they both call django.setup. Importing a module multiple times will only run it once.

Leave a comment