2

I have made the following directory structure:

project
    main_app
        settings
            base.py
            local.py
            production.py
    ...
    manage.py

I started local.py with:

from .base import *

I update manage.py as follows (mentioned here):

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.local")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

Running my unit tests works. I run the server locally, which works. Making calls to the API works. I then call a script, in which I have the following:

from django.conf import settings

data_dir = Path(settings.BASE_DIR) / 'csv'

When I run this script however, I get the following error upon loading the object settings:

django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.

When I print the settings module in class Settings in django/conf/__init__.py, I see that it takes the wrong settings file (which does not exist):

class Settings(BaseSettings):
    ...
    print('Settings module: {}'.format(settings_module))
    print('DJANGO_SETTINGS_MODULE: {}'.format(os.environ['DJANGO_SETTINGS_MODULE']))

Settings module: project.settings
DJANGO_SETTINGS_MODULE: project.settings

Why doesn't it take the correct settings file, as indicated in manage.py? I read here that it might be a circular reference in middleware, but I can't find it. This is my middleware setting:

MIDDLEWARE_CLASSES = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
]

When I echo the environment variable $DJANGO_SETTINGS_MODULE in a shell, I get an empty line back. To check if the environment variable is set somewhere in my project, I search for it explicitly in the terminal.

$ pwd
/Applications/XAMPP/htdocs/project/src
$ sift DJANGO_SETTINGS_MODULE
Binary file matches: project/__pycache__/wsgi.cpython-35.pyc
main_app/wsgi.py:os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main_app.settings.local")
Binary file matches: fe_import/__pycache__/CsvReader.cpython-35.pyc
fe_import/CsvReader.py:    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main_app.settings.local") ==> This is the script I am running
manage.py:    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main_app.settings.local")
Community
  • 1
  • 1
physicalattraction
  • 6,485
  • 10
  • 63
  • 122
  • Can you `echo $DJANGO_SETTINGS_MODULE` in your shell? If it's set, it will override the default set in your `manage.py`. Could you also paste the full content of your updated `manage.py` script? – knbk Dec 18 '15 at 12:45
  • I have updated the question with this additional information. – physicalattraction Dec 18 '15 at 13:14

2 Answers2

2

Running my unit tests works. I run the server locally, which works. Making calls to the API works. I then call a script, in which I have the following:

How do you call your script? Clearly not via manage.py.

This line:

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.local")

needs to appear in every script.

Also, be sure that there is nothing around that is overriding the value for DJANGO_SETTINGS_MODULE, and nothing that is manually calling settings.configure().


Tip: to avoid repeating the same code over and over again, and to avoid problems of this kind, I often use custom management commands instead of writing my own scripts.

Andrea Corbellini
  • 17,339
  • 3
  • 53
  • 69
  • Indeed I was not running it through `manage.py`. I now copied that line into my script before loading the settings object. However, I still get the same error. – physicalattraction Dec 18 '15 at 13:25
  • @physicalattraction: in `conf/__init__.py`, other than printing the settings module name, try printing the value for `DJANGO_SETTINGS_MODULE`. Also, be sure not to call `settings.configure()` (and not to call `DJANGO_SETTINGS_MODULE` twice) – Andrea Corbellini Dec 18 '15 at 13:26
  • The environment variable is set to the same as the settings module name, I have updated that now in the question. I (think I) am not explicitly calling `settings.configure()` or `DJANGO_SETTINGS_MODULE` twice, unless that is what happens with the line `from django.conf import settings`. – physicalattraction Dec 18 '15 at 13:32
  • @physicalattraction: somewhere, something is overriding the env var. Try `grep -r DJANGO_SETTINGS_MODULE` and be sure that `DJANGO_SETTINGS_MODULE` is really unset when you call your script (remember, `setdefault()` works only if the env var is not set) – Andrea Corbellini Dec 18 '15 at 13:35
  • Indeed, the environment variable is set already! I am running it automatically in Eclipse. When I set the environment variable instead of using `setdefault`, the problem disappears! :-) – physicalattraction Dec 18 '15 at 13:40
  • @physicalattraction: you should tell Eclipse not to set the variable. Avoiding `setdefault()` is not a solution: if you do so you won't be able to set `DJANGO_SETTINGS_MODULE=project.settings.production` from the command line! – Andrea Corbellini Dec 18 '15 at 13:46
  • Do you happen to know how to do this? In the Run Configuration, in the tab Environment, everything is empty already. – physicalattraction Dec 18 '15 at 14:40
0

I dont know if it helps, but i will tell what i know and how we do this. First of all its a bad idea to patch manage.py. I believe this file need to be untouched. We have following setup: one settings.py contains settings and variables for project. Near it we have local.py. and in the settings we have: import * from local. this file lives on a local machine and have something like this:

#database settings for sqlite
#passwords for apis
debug=True

then we have to add this file to .gitignore so after git pull from production we wont be have this file on production server. On production we create another local.py

#database settings for production database
#passwords for apis
debug=False

So local is mean not development but "local for this machine"

Dmitry Yudin
  • 1,033
  • 1
  • 10
  • 31
  • I am following the convention from the book Two Scoops of Django, which to be honest seems to be a better way of handling different settings files. – physicalattraction Dec 18 '15 at 12:52
  • 1
    It's entirely valid to patch `manage.py` to suit your needs. It's part of your project, not your Django installation. – knbk Dec 18 '15 at 12:58