Code

Opened 16 months ago

Closed 16 months ago

Last modified 16 months ago

#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)

default-manage-py.patch (755 bytes) - added by jamercee 16 months ago.
django-manage.py patch (git-diff formatted)

Download all attachments as: .zip

Change History (5)

Changed 16 months ago by jamercee

django-manage.py patch (git-diff formatted)

comment:1 Changed 16 months ago by carljm

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to 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 Changed 16 months ago by jamercee

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 Changed 16 months ago by carljm

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 Changed 16 months ago by jamercee

  • Resolution changed from worksforme to 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).

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.