4

I have the following script and it's meant to be a standalone Django script so I can run python my_script.py from the command line. It used to work with Django 1.8, after I upgrade to Django 1.11, I'm getting the following error:

Traceback (most recent call last):
  File "app.py", line 8, in <module>
    django.setup()
  File "C:\python27\lib\site-packages\django-1.11.5-py2.7.egg\django\__init__.py", line 22, in setup
    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
  File "C:\python27\lib\site-packages\django-1.11.5-py2.7.egg\django\conf\__init__.py", line 56, in __getattr__
    self._setup(name)
  File "C:\python27\lib\site-packages\django-1.11.5-py2.7.egg\django\conf\__init__.py", line 41, in _setup
    self._wrapped = Settings(settings_module)
  File "C:\python27\lib\site-packages\django-1.11.5-py2.7.egg\django\conf\__init__.py", line 110, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "C:\python27\lib\importlib\__init__.py", line 37, in import_module
    __import__(name)
ImportError: Import by filename is not supported.

This is my python script

# standalone django setup
import os, sys, logging, django
prj_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
logging.basicConfig(level=logging.INFO)
logging.info("PRJ_DIR: %s" % prj_dir)
sys.path.append(prj_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "%s.settings" % prj_dir.split("/")[-1])
django.setup()

...
...
2
  • 1
    Could you please share your settings.py? Because there is not way I can reproduce your issue, and I suspect it could be related with the settings file. Thanks in advance Commented Sep 12, 2017 at 16:19
  • 1
    you are using this file in the same folder as manage.py? Commented Sep 14, 2017 at 3:33

6 Answers 6

8
+25

It seems you're trying to split a file path by the forward slash / while running your script on Windows where path separator is the backslash \. Use os.path.basename instead of manually dealing with the stings (.split("/")[-1]):

>>> import os
>>> os.path.basename(r'/home/user/project')
'project'
>>> os.path.basename(r'c:\users\user\project')
'project'

In comparison:

>>> r'/home/user/project'.split("/")[-1]
'project'  # works
>>> r'c:\users\user\project'.split("/")[-1]
'c:\\users\\user\\project'  # error
Sign up to request clarification or add additional context in comments.

Comments

4

Don't reinvent the wheel. There is a cool manage command on django extensions that lets you run scripts on the django context.

https://django-extensions.readthedocs.io/en/latest/runscript.html

1 Comment

That could be off topic for OP, but very interesting. (It does not do what is usually expected in questions about a standalone Django script.) Your link is inspirative in the combination with Burhan Khalid's link to "Lightweight Django" to write a simple script for easy testing SO answers with tags django-orm and django-queryset before posting: the models, the customized settings and example in a single file, everything other common for many questions in another file :-)
1

Others have pointed out an issue with your path manipulation, however the cause of your actual import exception is that you are setting DJANGO_SETTINGS_MODULE to the name of a file.

It needs to be the name of a Python module. In other words, your settings file should end in .py and you should pass the name of it (without .py), or the importable path to it - exactly as you would type it in an import statement.

If your settings are in my_settings.py, then you would set the variable to my_settings.

Here is a simplified example of a one-page django application taken from the excellent Lightweight Django book's excerpt:

import sys


from django.conf import settings


settings.configure(
    DEBUG=True,
    SECRET_KEY='thisisthesecretkey',
    ROOT_URLCONF=__name__,
    MIDDLEWARE_CLASSES=(
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ),
)


from django.conf.urls import url
from django.http import HttpResponse


def index(request):
    return HttpResponse('Hello World')


urlpatterns = (
    url(r'^$', index),
)


if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

1 Comment

You are generally right, however it is clear that prj_dir is (should be) set correctly the parent directory of the script directory on all platforms by this code, without any ".py". If it would be a linux name it is also split correctly, the result is "DJANGO_SETTINGS_MODULE='parentdir.settings'. Invalid "\\" character is the problem, but an added ".py" would be "ImportError: No module named py". (Thanks for Lightweight Django.)
0

The error is in

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "%s.settings" % prj_dir.split("/")[-1])

If you run this script from the same folder as manage.py, it will return the name of the manage.py folder instead settings.py folder resulting managepy_folder.settings

when it should output settingspy_folder.settings to access the app

Test with :

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settingspy_folder.settings")

if it that was the problem, if you want use the same algorithm or something similar in multiple projects, you need a pattern to modify the current folder name to indicate the settings.py folders name, using the same folders name in both wouldn't require modification.

if that doesn't fix please post your settings.py file

Comments

0

If your script is in the same folder as settings.py, the code should be like this:

import os, sys, logging, django
prj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
logging.basicConfig(level=logging.INFO)
logging.info("PRJ_DIR: %s" % prj_dir)
sys.path.append(prj_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(os.path.basename(prj_dir)))
django.setup()

else, if your script is in the parent folder of settings.py:

import os, sys, logging, django
prj_dir = os.path.dirname(os.path.abspath(__file__))
logging.basicConfig(level=logging.INFO)
logging.info("PRJ_DIR: %s" % prj_dir)
sys.path.append(prj_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(os.path.basename(prj_dir)))
django.setup()

Comments

0

in the line: os.environ.setdefault( "DJANGO_SETTINGS_MODULE", "myproject.settings") # should be like in import command )

Just use python module path: like "myproject.settings" instead of path like /opt/myproject/settings" or "c:\myproject\settings.py"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.