#20109 closed New feature (invalid)
django-admin.py does not correctly set DJANGO_SETTINGS_MODULE (patch attached)
Reported by: | jamercee | Owned by: | nobody |
---|---|---|---|
Component: | Core (Management commands) | Version: | 1.5 |
Severity: | Normal | Keywords: | djang-admin.py, manage.py, "DJANGO_SETTINGS_MODULE" |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The default manage.py script (created by django-admin.py startproject) does not "correctly" set DJANGO_SETTINGS_MODULE in a way that permits running manage.py from another directory.
We discovered this while working on a custom manage.py command (https://docs.djangoproject.com/en/dev/howto/custom-management-commands). When trying to run our new command from a directory that was not within our project folder, the command extensions were not available. Our extensions were only visible when the manage.py command is run from withing our project folder.
The quick fix was to add our project path to sys.path.
But a better solution is to add this to the django/conf/project_template/manage.py template file. Something such as this:
diff --git a/django/conf/project_template/manage.py b/django/conf/project_template/manage.py index 391dd88..656deaf 100755 --- a/django/conf/project_template/manage.py +++ b/django/conf/project_template/manage.py @@ -1,8 +1,15 @@ #!/usr/bin/env python +import inspect import os import sys if __name__ == "__main__": + __script__ = inspect.getfile(inspect.currentframe()) + __script__ = os.path.realpath(os.path.abspath(__script__)) + __dname__ = os.path.dirname(os.path.dirname(__script__)) + if __dname__ not in sys.path: + sys.path.insert(0, __dname__) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings") from django.core.management import execute_from_command_line
Attachments (1)
Change History (5)
by , 12 years ago
Attachment: | default-manage-py.patch added |
---|
comment:1 by , 12 years ago
Resolution: | → worksforme |
---|---|
Status: | new → closed |
Hi, thanks for the report. The report doesn't make sense to me, because as far as I know Python always adds the directory of the running script to the beginning of sys.path
, no matter where you run it from, so the added code you propose should be entirely redundant. Demo:
[11:32] carljm@endive:~/tmp {test33} $ cat foo/manage.py #!/usr/bin/env python import sys print(sys.path) [11:32] carljm@endive:~/tmp {test33} $ python foo/manage.py ['/home/carljm/tmp/foo', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/distribute-0.6.28-py3.3.egg', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg', '/home/carljm/.venvs/test33/lib/python33.zip', '/home/carljm/.venvs/test33/lib/python3.3', '/home/carljm/.venvs/test33/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/lib-dynload', '/opt/Python-3.3.0/lib/python3.3', '/opt/Python-3.3.0/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/site-packages'] [11:32] carljm@endive:~/tmp {test33} $ ./foo/manage.py '['/home/carljm/tmp/foo', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/distribute-0.6.28-py3.3.egg', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg', '/home/carljm/.venvs/test33/lib/python33.zip', '/home/carljm/.venvs/test33/lib/python3.3', '/home/carljm/.venvs/test33/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/lib-dynload', '/opt/Python-3.3.0/lib/python3.3', '/opt/Python-3.3.0/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/site-packages'] [11:32] carljm@endive:~/tmp {test33} $ cd foo [11:32] carljm@endive:~/t/foo {test33} $ python manage.py ['/home/carljm/tmp/foo', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/distribute-0.6.28-py3.3.egg', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg', '/home/carljm/.venvs/test33/lib/python33.zip', '/home/carljm/.venvs/test33/lib/python3.3', '/home/carljm/.venvs/test33/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/lib-dynload', '/opt/Python-3.3.0/lib/python3.3', '/opt/Python-3.3.0/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/site-packages'] [11:32] carljm@endive:~/t/foo {test33} $ ./manage.py ['/home/carljm/tmp/foo', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/distribute-0.6.28-py3.3.egg', '/home/carljm/.venvs/test33/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg', '/home/carljm/.venvs/test33/lib/python33.zip', '/home/carljm/.venvs/test33/lib/python3.3', '/home/carljm/.venvs/test33/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/lib-dynload', '/opt/Python-3.3.0/lib/python3.3', '/opt/Python-3.3.0/lib/python3.3/plat-linux', '/home/carljm/.venvs/test33/lib/python3.3/site-packages']
No matter where I run manage.py
from, /home/carljm/tmp/foo
(its location) is always the first entry on sys.path
. I verified this under both Python 2 and Python 3. So it seems there must be something else unusual going on in your situation.
(Also, it seems your proposed code could be simplified by using the builtin __file__
rather than inspect.getfile(inspect.currentframe())
.)
comment:2 by , 12 years ago
I should have been more specific in my comment. I did not mean to imply the location path was not added to sys.path. I was trying to suggest that unless you run ./manage.py from within the project folder -- it cannot find the command extensions (only the stock extensions).
If you examine the code, you'll notice it is not adding the path of the script -- but the parent path.
The default manage.py set's the DJANGO_SETTINGS_MODULE to a path that includes the project name:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
This means the caller needs to set the path to include the parent folder BEFORE invoking ./manage.py. The mod we propose would do this by default and save the caller/user from having to do this for themselves (or to always modifying their manage.py by hand after creating a new project).
Regarding using inspect() rather than file. We've developed this particular recipe over several years to account for the various platform differences within python (windows, vs. unix vs virtualenv, fronzen binaries, etc...). There's some discussion of these issues over at stackoverflow
http://stackoverflow.com/questions/50499/in-python-how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executin
http://stackoverflow.com/questions/247770/retrieving-python-module-path
http://stackoverflow.com/questions/10293808/how-to-get-the-path-of-the-executing-frozen-script
I'll admit the solution "might" be overkill -- but in my experience it works reliably on every platform (even if it's a bit verbose).
comment:3 by , 12 years ago
You shouldn't need the parent directory on sys.path
and you'll be better off fixing your project layout to not require that; having two nested directories both on sys.path
results in problems like modules that can be imported under two different names (and thus might be executed twice). It might be helpful to review https://docs.djangoproject.com/en/dev/releases/1.4/#updated-default-project-layout-and-manage-py
comment:4 by , 12 years ago
Resolution: | worksforme → invalid |
---|
My entire problem report is invalid. Please disregard.
We are still using the Django 1.3 project layout with new Django 1.5 code. The new project format correctly finds the custom management commands no matter what path you call it from.
(sorry for the waste of time).
django-manage.py patch (git-diff formatted)