AttributeError: 'Settings' object has no attribute 'ROOT_URLCONF' on Heroku
The problem occurred because I have switched from a single settings file to a settings package, updated the references in manage.py
, so it works locally, but didn't reflect that in wsgi.py
which is what configures the server on Heroku.
wsgi.py
now sets environment-specific settings:
os.environ["DJANGO_SETTINGS_MODULE"] = "main.settings." + os.environ["ENV"]
KindOfGuy
Learning to love Django, but falling in love with StackOverflow faster. Making web apps for blue-sky, social good.
Updated on June 13, 2022Comments
-
KindOfGuy almost 2 years
I am getting this error when I deploy to Heroku:
2014-05-07T11:50:06.927955+00:00 heroku[router]: at=info method=GET path=/favicon.ico host=staging.mysite.com request_id=eead056c-f89d-4fcd-b282-71a023631a71 fwd="80.237.234.148" dyno=web.1 connect=1ms service=4ms status=500 bytes=238 2014-05-07T11:50:06.925723+00:00 app[web.1]: 2014-05-07 06:50:06 [7] [ERROR] Error handling request 2014-05-07T11:50:06.925732+00:00 app[web.1]: Traceback (most recent call last): 2014-05-07T11:50:06.925746+00:00 app[web.1]: urlconf = settings.ROOT_URLCONF 2014-05-07T11:50:06.925735+00:00 app[web.1]: File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 126, in handle_request 2014-05-07T11:50:06.925738+00:00 app[web.1]: respiter = self.wsgi(environ, resp.start_response) 2014-05-07T11:50:06.925740+00:00 app[web.1]: File "/app/.heroku/python/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 241, in __call__ 2014-05-07T11:50:06.925742+00:00 app[web.1]: response = self.get_response(request) 2014-05-07T11:50:06.925744+00:00 app[web.1]: File "/app/.heroku/python/lib/python2.7/site-packages/django/core/handlers/base.py", line 82, in get_response 2014-05-07T11:50:06.925751+00:00 app[web.1]: return func(self._wrapped, *args) 2014-05-07T11:50:06.925749+00:00 app[web.1]: File "/app/.heroku/python/lib/python2.7/site-packages/django/utils/functional.py", line 185, in inner 2014-05-07T11:50:06.925753+00:00 app[web.1]: AttributeError: 'Settings' object has no attribute 'ROOT_URLCONF'
Locally it works fine, and in the remote bash shell, it seems that django can access ROOT_URLCONF, as I am running:
~ $ python manage.py shell Python 2.7.4 (default, Apr 6 2013, 22:14:13) In [2]: from django.conf import settings In [3]: settings.ROOT_URLCONF Out[3]: 'urls'
The settings file therefore seems accessible to manage.py and includes the correct ROOT_URLCONF variable.
I have tried very many configurations with no luck. Any ideas?
Here are my current manage.py and settings configurations (env variable ENV is set to staging here):
# manage.py #!/usr/bin/env python import os import sys environment = os.environ['ENV'] if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'main.settings.' + environment) from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)
settings/ folder contains an empty __init__.py and:
# staging.py from .base import * MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django_facebook.auth_backends.FacebookBackend', 'fandjango.middleware.FacebookMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', # 'debug_toolbar.middleware.DebugToolbarMiddleware', # Uncomment the next line for simple clickjacking protection: # 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'south', 'crewcal', 'django_extensions', 'registration', 'django_facebook', 'fandjango', 'django.contrib.humanize', 'storages', 'datetimewidget', 'postman', 'notification', # 'raven.contrib.django.raven_compat', # Uncomment the next line to enable the admin: 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', ) # base.py ENV = 'DEVELOPMENT' import os import sys MAIN_APP_DIR = os.path.dirname(__file__) PROJECT_NAME = MAIN_APP_DIR.split('/')[-1] project_root = lambda f: os.path.abspath(os.path.join(MAIN_APP_DIR, '../../', f)) PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) PROJECT_DIR = os.path.join(PROJECT_ROOT,'../../crewcal') WEB_ROOT = project_root('webroot') sys.path.insert(0, os.path.join(MAIN_APP_DIR, '../')) sys.path.insert(0, MAIN_APP_DIR) dev = 'DEVELOPMENT' DEBUG = (ENV is dev) TEMPLATE_DEBUG = DEBUG TESTING = 'test' in sys.argv ADMINS = ( ('Me', '[email protected]'), ) MANAGERS = ADMINS DATABASE_CONFIGS = { 'DEVELOPMENT': { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'ssc', # Or path to database file if using sqlite3. 'USER': 'postgres', # Not used with sqlite3. 'PASSWORD': 'xxx', # Not used with sqlite3. 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } }, } DATABASES = DATABASE_CONFIGS[ENV] SITE_ID = 1 # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = False # If you set this to False, Django will not format dates, numbers and # calendars according to the current locale. USE_L10N = True gettext = lambda s: s LANGUAGES = (('en', gettext('English')),) MEDIA_ROOT = os.path.join(WEB_ROOT, 'media') MEDIA_URL = '/media/' STATIC_ROOT = os.path.join(PROJECT_DIR, 'static') AWS_ACCESS_KEY_ID = 'SECRET' AWS_SECRET_ACCESS_KEY = 'SECRET' AWS_STORAGE_BUCKET_NAME = 'vvv' # URL prefix for static files. # Example: "http://media.lawrence.com/static/" try: if os.environ['ENV'] == 'staging' or 'production': STATIC_URL = 'https://s3-eu-west-1.amazonaws.com/vvv/' except: STATIC_URL = '../mysite/static/' # Additional locations of static files STATICFILES_DIRS = ( # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) # List of finder classes that know how to find static files in # various locations. STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 'django.contrib.staticfiles.finders.DefaultStorageFinder', ) # Make this unique, and don't share it with anybody. SECRET_KEY = os.environ['SECRET_KEY'] # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', # 'django.template.loaders.eggs.Loader', ) try: if os.environ['ENV'] == 'staging' or 'production': EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' except: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_FILE_PATH = ( #os.path.join(SITE_ROOT, '/app-email-messages') # change this to a proper location) ) ACCOUNT_ACTIVATION_DAYS = 7 EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = '[email protected]' EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD'] EMAIL_PORT = 587 EMAIL_USE_TLS = True POSTMAN_AUTO_MODERATE_AS = True ROOT_URLCONF = 'main.urls' # Python dotted path to the WSGI application used by Django's runserver. WSGI_APPLICATION = 'wsgi.application' PROJECT_PATH = os.path.realpath(os.path.dirname(os.path.dirname(__file__))) TEMPLATE_DIRS = ( os.path.join(PROJECT_PATH, 'templates/'), # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage' FACEBOOK_APP_ID = 'app-id' FACEBOOK_APP_SECRET = os.environ['FACEBOOK_APP_SECRET'] # fandjango settings FACEBOOK_APPLICATION_ID = 'app-id' FACEBOOK_APPLICATION_SECRET_KEY = os.environ['FACEBOOK_APP_SECRET'] FACEBOOK_APPLICATION_NAMESPACE = 'me' try: if os.environ['DOMAIN'] == 'crew': DOMAIN = 'crew' EVENT_PUB_COMMITTED_CRITICAL_MASS = 3 elif os.environ['DOMAIN'] == 'staging': DOMAIN = 'staging' EVENT_PUB_COMMITTED_CRITICAL_MASS = 2 except: DOMAIN = 'crew' EVENT_PUB_COMMITTED_CRITICAL_MASS = 3 try: if os.environ['ENV'] == 'staging': MAX_PROPOSED_EVENTS = 3 except: MAX_PROPOSED_EVENTS = 300 POSTMAN_DISALLOW_ANONYMOUS = True POSTMAN_AUTO_MODERATE_AS = True INTERNAL_IPS = ('127.0.0.1',) LOGIN_URL = '/login' LOGOUT_URL = '/logout' LOGIN_REDIRECT_URL = "/user" AUTH_PROFILE_MODULE = 'me.UserProfile' AUTHENTICATION_BACKENDS = ( 'crewcal.backends.EmailOrUsernameModelBackend', 'django.contrib.auth.backends.ModelBackend', 'django_facebook.auth_backends.FacebookBackend', 'insensitive.backends.CaseInsensitiveModelBackend' ) # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. # See http://docs.djangoproject.com/en/dev/topics/logging for # more details on how to customize your logging configuration. LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse' } }, 'handlers': { 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django.request': { 'handlers': ['mail_admins'], 'level': 'ERROR', 'propagate': True, }, } } TEMPLATE_CONTEXT_PROCESSORS = ( "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.core.context_processors.static", "django.core.context_processors.request", "django.core.context_processors.tz", "django.contrib.messages.context_processors.messages", "django_facebook.context_processors.facebook" ) try: if os.environ['ENV'] == 'production': DEBUG = False ALLOWED_HOSTS = ['me.org.uk',] # Parse database configuration from $DATABASE_URL import dj_database_url DATABASES['default'] = dj_database_url.config() # Honor the 'X-Forwarded-Proto' header for request.is_secure() SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') if os.environ['ENV'] == 'staging': DEBUG = False ALLOWED_HOSTS = ['me.org.uk',] # Parse database configuration from $DATABASE_URL import dj_database_url DATABASES['default'] = dj_database_url.config() # Honor the 'X-Forwarded-Proto' header for request.is_secure() SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') except: pass