Django: where is settings.py looking for imports, and why? - python

I have a Django app with a common directory structure:
project
---manage.py
---app
---__init__.py
---settings.py
---settings_secret.py
---a bunch of other files for the app itself
That settings_secret.py file contains variables from secrets.py which I do not want to send to github. For some reason, I cannot seem to import it into settings.py. First 5 lines of settings.py:
# Django settings for project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
import os
from settings_secret import *
Which fails with the partial stacktrace:
File "/foo/bar/project/app/settings.py", line 5, in <module> from settings_secret import *
ImportError: No module named 'settings_secret'
To debug, I created a test file inside /project/ like so:
from settings_secret import *
print(VARIABLE_FROM_SETTINGS_SECRET)
Which worked like a charm. So clearly, settings.py isn't looking in the right place for settings_secret. So where is it looking?

In settings.py, you should do: from .settings_secret import *
It works with the . because the proper syntax is supposed to be:
from app.settings_secret import *
Removing the app is shorthand coding, but the same principle applies. You need to tell Django to look for the directory (app), and then you are specifying which file in that directory to look for.
If you just did, from settings_secret import *, you are telling Django to look for the directory settings_secret, which doesn't exist.
Does that make sense to you?

Related

calling settings.py from another python scripts

I have .env file where I have added environment settings. I wrote "settings.py" which reads .env file and stores values of settings. I want to import settings.py from other_script.py. But I am getting None as value.
I tried to execute "settings.py" and returns a value. On the other hand when I execute other_script which imports settings, the values become None value.
settings.py:
import os
from dotenv import load_dotenv
from pathlib import Path
env_path = Path('.') / '.env'
load_dotenv(env_path)
MONGO_IP = os.getenv("MONGO_IP")
MONGO_PORT = os.getenv("MONGO_PORT")
MONGO_DB = os.getenv("MONGO_DB")
print(MONGO_DB)
other_script.py:
from pymongo import MongoClient
from settings import MONGO_IP, MONGO_PORT, MONGO_DB
print(MONGO_DB)
mongo_client = MongoClient(MONGO_IP, MONGO_PORT)[MONGO_DB]
So when I execute other_script.py, keys should return a value. What do I miss?
Two things to check are:
settings.py and other_script.py are in the same folder. Without this, other_script.py will not be able to find settings.py.
Look at your env and see if load_dotenv(env_path) is working properly. If env values for MONGO_* are not set properly you cannot read them.
If they are not in the same folder, the issue perhaps is that you don't have an __init__.py file in the folder you want to import from, since it is needed to make it a package. The init file can be empty.

Writing doctests for pyramid web app which depend on settings in ini file

I would like to write doctests for my pyramid web app, using the webtest module. I tried it like this:
from my_webapp import main
from webtest import TestApp
app = TestApp(main({}))
result = app.get('/')
This raises a KeyError (because some.url is not known) when my code reaches this line:
url = request.registry.settings['some.url']
The value of some.url is specified in the paster ini file of my application. Is there a simple way to use my development.ini when running my test code? I did not yet fully understand how/when the ini file is loaded during pyramid start up, so it's hard to figure out where to load it while testing.
main is invoked with the contents of your ini file. A simple way to load your app from an ini is:
from pyramid.paster import get_app
app = get_app('testing.ini#main')
test_app = TestApp(app)
This expects "testing.ini" to be in the current working directory, so you may need to tweak that. If you'd like it to be relative to a spot in your tree you can use:
import os.path
import some_module
here = os.path.dirname(some_module.__file__)
app = get_app(os.path.join(here, 'testing.ini'))

New django project: Cannot import name connections

I'm having a problem with Django. If you could help me, I'd very much appreciate it.
So, I've found lots of people with a similar problem, but none of the "solutions" work for me. I'm learning how to use django and I've successfully installed it.
But, I get an error when executing the import from the init.py file:
from django.db import connections
Here's the error:
raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e))
ImportError: Could not import settings 'TestProject.settings' (Is it on sys.path?): cannot import name connections
The containing django folder is included on my PYTHONPATH, and my file structure looks like this:
TestProject
--manage.py
--TestProject
----__init__.py
----settings.py
etc.
This is my manage.py file:
#!/usr/bin/env python import os import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TestProject.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
I don't really know how to troubleshoot this. I'm also new to Python, so forgive me if this is completely obvious to someone else.
Thanks for your help.
This is a weird quirk indeed. I found the following to work in my program:
Import django settings.
Set the default environment.
ACCESS e.g. SITE_ID (or another property, but just use e.g. SITE_ID) through settings.
Finally, you should be able to import.
E.g.
from django.conf import settings
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
settings.SITE_ID
or use another variable like DEBUG; note.. this line does nothing.. it just accesses the settings and seems to 'activate' the environment. You could also do a simple print statement like print settings.SITE_ID, but that's not necessary.)
from myapp.models import MyModel, MyOtherModel
If you do everything in that order.. well it worked for me! The magic happens when you access an actual setting before you do the import of a model.
I think this might be a bug/error in Django 1.5

Django AttributeError in settings.py file

I've been stuck all day on what seems to be a very silly import problem. From my Django project directory, I can import a module and run a function just fime:
(msg-gw)slashingweapon:~/msg-gw/www$ python
>>> import snpp
>>> snpp.config_url('snpp://server.name.com:1234?user=me&pass=whatever')
{'host': 'server.name.com', 'pass': 'whatever', 'port': 1234, 'user': 'me'}
But when I try to run my app, either through manage.py or by gunicorn, I get an attribute error:
(msg-gw)slashingweapon:~/msg-gw/www$ python manage.py runserver 8000
File "/home/slashingweapon/msg-gw/www/project/settings.py", line 26, in <module>
SNPP = snpp.config_url('snpp://server.name.com:1234?user=me&pass=whatever')
AttributeError: 'module' object has no attribute 'config_url'
The two relevant lines in my settings.py file are exactly what you would expect. Notice that I can import the module just fine, but the config_url() function isn't found.
import snpp
SNPP = snpp.config_url('snpp://server.name.com:1234?user=me&pass=whatever')
The directory layout is exactly what you would expect:
www
|
+-project
| +-__init__.py
| +-settings.py
| +-urls.py
| +-views.py
| +-wsgi.py
|
+-snpp
+-__init__.py
+-protocol.py
+-views.py
+-urls.py
The config_url() function is defined inside snpp/__init__.py
I have tried all kinds of things:
from snpp import config_url
move config_url to the file snpp/config and then import with
import snpp.confg
from snpp.config import config_url
from snpp import config and then invoke through config.config_url()
The __init__.py file is nothing special. It just lets you encode some server information as a string, so you can stick your SNPP config into the environment:
import urlparse
def config_url(urlStr):
config = {
'host':None,
'port':444,
'user':None,
'pass':None,
}
url = urlparse.urlparse(urlStr)
if url.scheme == 'snpp':
locParts = url.netloc.split(":")
config['host'] = locParts[0]
if len(locParts) > 1:
port = int(locParts[1])
if port > 0:
config['port'] = port
args = urlparse.parse_qs(url.query)
config['user'] = args.get('user', [None])[0]
config['pass'] = args.get('pass', [None])[0]
return config
I am using Python 2.7, django 1.5.1, and virtualenv.
Other parts of my project work well. When I print out the path in my browser, it looks correct. Importing snpp should not be a problem, since snpp is in the www directory:
/home/slashingweapon/msg-gw/www
/home/slashingweapon/msg-gw/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg
/home/slashingweapon/msg-gw/lib/python2.7/site-packages/pip-1.3.1-py2.7.egg
/home/slashingweapon/msg-gw/lib/python2.7/site-packages/django_json_rpc-0.6.2-py2.7.egg
/home/slashingweapon/msg-gw/lib/python27.zip
/home/slashingweapon/msg-gw/lib/python2.7
... etc ...
It doesn't matter if the snpp module is in my INSTALLED_APPS list or not. I get the same result.
Solved
With the help of SO denizens, I found the problem.
I had refactored my application by moving some reusable code pieces from the project directory to the new snpp directory. When I did that, I neglected to move or delete the *.pyc files.
The value of snpp.__file__ was:
/home/slashingweapon/msg-gw/www/project/snpp.pyc
instead of the expected:
/home/slashingweapon/msg-gw/www/snpp/__init__.pyc
During the import process, Python was looking in project/ before snpp/ and finding an old snpp.pyc file. It would import the old pyc file and be satisfied, thus ignoring the entire snpp/ dir.
Had I been a little sharper (or a little more experienced with Python) I might have noticed that I was getting some strange import behavior in general whenever I tried to import anything from snpp/. It should have occurred to me that the whole module was wonky, and not just the one function I was trying to use at the moment.
Check what exactly is being imported by using
snpp.__file__
right after import snpp statement.
Actually import might not be from the path you are expecting to see.

ImportError and Django driving me crazy

OK, I have the following directory structure (it's a django project):
-> project
--> app
and within the app folder, there is a scraper.py file which needs to reference a class defined within models.py
I'm trying to do the following:
import urllib2
import os
import sys
import time
import datetime
import re
import BeautifulSoup
sys.path.append('/home/userspace/Development/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
from project.app.models import ClassName
and this code just isn't working. I get an error of:
Traceback (most recent call last):
File "scraper.py", line 14, in
from project.app.models import ClassName
ImportError: No module named project.app.models
This code above used to work, but broke somewhere along the line and I'm extremely confused as to why I'm having problems. On SnowLeopard using python2.5.
import sys
sys.path.append ('/path/to/the/project')
from django.core.management import setup_environ
import settings
setup_environ(settings)
from app.models import MyModel
Whoa whoa whoa. You should never ever have to put your project name in any of your app code. You should be able to reuse app code across multiple projects with no changes. Pinax does this really well and I highly recommend checking it out for a lot of django best practices.
The worst thing you could do here is to hard code your absolute path into your app or settings. You shouldn't do this because it will break during deployment unless you do some import local_settings hacking.
If you have to access the project root directory, try what pinax has in settings.py...
import os.path
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
The thing is that it looks like you are trying to access the models module within the same app and this is waaay easier.
To import models.py inside scraper.py in the same directory just use import models or import models as app_models if you already have something named models in scraper.py (django.db.models for instance). Are you familiar with Python module conventions?
However, the best way is probably to stick with the django idiom, from ... import ... statement:
from app import models
If this doesn't work automatically, then something is wrong in your settings.py.
You don't indicate if project is located in /home/userspace/Development/. I'll assume that it is.
Make sure there's an (empty by default) file named __init__.py in project and another one in app.
EDIT: Next thing to try: Fire up the Python command line in the script's directory and try the following:
import project
import project.app as app
import project.app.models as models
models.__dict__.keys()
Do they all work? If so, what is the last line's output? If not, which dies first?

Categories