Search code examples
djangopostgresqldjango-modelspostgis

Collectstatic returns KeyError due to dj_database_url()


I'm implementing dj_database_url but receiving an error upon running collectstatic.

Following the the dj_database_url readme, as well as the steps outlined by Heroku here, I added this to the bottom of my settings.py:

import dj_database_url

DATABASES['default'] =  dj_database_url.config(default='postgis://USER:PASSWORD@HOST:PORT/NAME')
DATABASES['default']['ENGINE'] = 'django.contrib.gis.db.backends.postgis'

GDAL_LIBRARY_PATH = os.getenv('GDAL_LIBRARY_PATH')
GEOS_LIBRARY_PATH = os.getenv('GEOS_LIBRARY_PATH')  

Upon adding, collectstatic will give me the this traceback:

Traceback (most recent call last):
  File "./manage.py", line 29, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 308, in execute
    settings.INSTALLED_APPS
  File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 56, in __getattr__
    self._setup(name)
  File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 41, in _setup
    self._wrapped = Settings(settings_module)
  File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 110, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/usr/src/app/config/settings/production.py", line 211, in <module>
    DATABASES['default'] =  dj_database_url.config(default='postgis://USER:PASSWORD@HOST:PORT/NAME')
  File "/usr/local/lib/python3.6/site-packages/dj_database_url.py", line 55, in config
    config = parse(s, engine, conn_max_age, ssl_require)
  File "/usr/local/lib/python3.6/site-packages/dj_database_url.py", line 103, in parse
    engine = SCHEMES[url.scheme] if engine is None else engine
KeyError: ''  

There's sparse docs on this issue in the wild. I did find this github issue: https://github.com/vitorfs/bootcamp/issues/78

Which recommends that I edit my ALLOWED_HOSTS. I've tried it to no avail.

This is the line of code referenced at the bottom of the traceback:
https://github.com/kennethreitz/dj-database-url/blob/master/dj_database_url.py#L103

From my understanding, it seems to expect an engine, which is a scheme(?) such as "sqlite", or "postgis". I do believe I am setting the proper engine. Does it need to be set anywhere else?

I tried reversing the code order to:

...
DATABASES['default']['ENGINE'] = 'django.contrib.gis.db.backends.postgis'
DATABASES['default'] =  dj_database_url.config(default='postgis://USER:PASSWORD@HOST:PORT/NAME')  

also to no avail.


Solution

  • The error is specific. You are trying to access a dictionary (SCHEMES) using an empty string as key (so url.scheme has '' as its value). Now, dj_database_url will first try to get URL from the DATABASE_URL environment value and if it does not find this variable only then the default will be used. From the error you get it is obvious that the default is not actually used so it tries to parse the url from the DATABASE_URL envirotnment variable. How are you running the collectstatic management command? Try explicitly setting DATABASE_URL before running it. For example, open a bash shell and run something like

    DATABASE_URL=postgis://USER:PASSWORD@HOST:PORT/NAME python manage.py collectstatic 
    

    (substituting the correct values of course). It should work when run like this.