I’m relative new to django and in generall to the python world. But I have experience with ruby (been working with rails for 2 years) so many concepts of python/django are not that new to me.
Anyway, I am writing an small package in python that will have a database connection and I want to use this package inside django but also in the feature outside django. So I decided take advantage of django.db and not worry about writing any database connection and managment stuff.
So I started writing my first models and wanted to make a first test outside of a django environment and I’m finding myself with some difficulties.
I thought about having the same configuration mechanism for my package as for any django application (I mean the settings.py file). I wrote a file (called nodjango_settings.py as a template) that only contains the DATABASES dictionary and added two custom variables to it:
MYAPP_DB_ID = "myappdb"
MYAPP_DB_PREFIX = "myapp_"
DATABASES = {
MYAPP_DB_ID: {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myappdb',
}
}
The directory structure of my package is:
.
|-- README.txt
|-- doc
| `-- db.txt
|-- setup.py
|-- src
| |-- __init__.py
| `-- myapp
| |-- __init__.py
| |-- exceptions.py
| |-- models.py
| |-- nodjango_settings.py
| `-- nodjango_settings.pyc
`-- test
`-- test.py
I was reading a little bit of djangos own code to see how to handle the DJANGO_SETTINGS_MODULE environment variable and read the configuration file, so added the following code to myapp/__init__py.
import os
# try to look after the DJANGO_SETTINGS_MODULE environment variable
# if not present raise an import error
# code abstract from python2.6/site-packages/django/conf/__init__.py
try:
settings_module = os.environ["DJANGO_SETTINGS_MODULE"]
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
raise ImportError("The DJANGO_SETTINGS_MODULE environment variable is not present.")
# TODO: look at python2.6/site-packages/django/conf/__init__.py +93
# if you print sys.path then the project directory gets added
# in django/core/management/__init__.py with sys.path.append
from django.utils import importlib
p = importlib.import_module(settings_module)
print p.MYAPP_DB_ID
I wanted to test that __init__.py works as intended so on the root directory of my package I ran:
$ DJANGO_SETTINGS_MODULE="src.myapp.nodjango_settings" python src/myapp/__init__.py
Traceback (most recent call last):
File "src/myapp/__init__.py", line 22, in <module>
p = importlib.import_module(settings_module)
File "/home/yanez/devpython/lib/python2.6/site-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
ImportError: No module named src.myapp.nodjango_settings
I didn’t expect that. When you create a new django application a manage.py file is created. And this file sets DJANGO_SETTINGS_MODULE the variable to the settings.py file from the perspective of the root directory of the application.
I read more code of django and realized that in django/core/management/__init__.py the root directory of the application is added to sys.path. This could also be the solution to my problem but I’m not quite sure whether it’s a good idea to mess with sys.path or not.
I’m not quite sure whether my idea is a good one or a bad one. I’d like to know what you think about it and where/how I can improve it. Beside, if I stick to my idea, how can I read my custom varaibles in settings.py without having to reimport the settings module over and over?
When deploying a django project with mod_wsgi, one have to write a wsgi (python) script, that does the “sys.path” dance and sets the DJANGO_SETTINGS_MODULE environment variable, then create the wsgi application object etc.
Why do I mention this ? Because, IMHO, you should not try to handle this part of the problem within “myapp”, but from a distinct python script that would be the application entry point when using your app outside a django project context, and keep “myapp” as a pure library package. This launcher script would then take care of setting up the correct environement (sys.path, settings, whatever). For the record, the settings module is just a Python module, which at runtime is an ordinary python object (instance of class “module”), and there are quite a few ways (other than the default import mechanism) to create a module instance and add it to sys.modules (which is the important point here).
As a side note, having the settings in the packages doesn’t make sense IMHO, it’s a configuration file.
Edit : well, I knew there was something about using part of django standalone, and here it is: https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-without-setting-django-settings-module