Search code examples
djangomongodbherokunosqldjongo

Django + Heroku + MongoDB Atlas (Djongo) = DatabaseError with No Exception


One line description of the issue

Whenever my django app deployed on heroku tries to access my MongoDB Atlas cluster to submit a form or check an admin login it throws something like the attached error.

Extra Details

Error reproducible on heroku build here

I think that this is error has to do with how heroku interacts with my MongoDB Atlas cluster, as I am able to get the app to successfully read and make modifications do different records in my database when I run the build locally.

I have enabled traffic from all IP addresses to my Atlas cluster, removed the default Heroku PostrgreSQL database from my Heroku app and the config variables, and stored my own database IP as a config var.

Any help would be greatly appreciated.

Python script


    # Model Script
    from django.db import models
    
    class RawRequest(models.Model):
        content = models.CharField(max_length=130)
        identifier = models.CharField(max_length=30)



    # Views Script
    from django.shortcuts import render
    from django.shortcuts import redirect
    from django.urls import reverse
    from django.http import HttpResponse
    from django.views.generic import CreateView
    from .models import RawRequest
    
    
    # Create your views here.
    def index(request):
        return HttpResponse("euler-calc terminal GUI")
    
    def potato(request):
        return HttpResponse("potato")
    
    class RequestView(CreateView):
            model = RawRequest
            fields = ('content', 'identifier')
            def get_success_url(self):
                return reverse('potato')


    """
    Django settings for eulercalc project.
    
    Generated by 'django-admin startproject' using Django 3.0.5.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/3.0/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/3.0/ref/settings/
    """
    
    import os
    import django_heroku
    
    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = # a secret
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'crispy_forms',
        'terminal',
    ]
    
    CRISPY_TEMPLATE_PACK = 'bootstrap4'
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'eulercalc.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'eulercalc.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
    
    DATABASES = {
            'default': {
                'ENGINE': 'djongo',
                'NAME': 'euler-calc',
                'CLIENT': {
                    'host': str(os.environ.get('MONGODB_URL')),
                    'authMechanism': 'SCRAM-SHA-1'
                }
            }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/3.0/topics/i18n/
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.0/howto/static-files/
    
    STATIC_URL = '/static/'
    
    # Activate Django-Heroku.
    django_heroku.settings(locals())

Traceback

Environment:


Request Method: POST
Request URL: https://euler-calc.herokuapp.com/

Django Version: 2.2.12
Python Version: 3.6.10
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'crispy_forms',
 'terminal']
Installed Middleware:
('whitenoise.middleware.WhiteNoiseMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')

Traceback:

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in parse
  842.                 return handler(self, statement)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in _insert
  907.         query = InsertQuery(self, self.db, self.connection_properties, sm, self._params)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in __init__
  339.         super().__init__(*args)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in __init__
  61.         self.parse()

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in parse
  409.         self._fill_values(statement)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in _fill_values
  367.                 raise SQLDecodeError

The above exception () was the direct cause of the following exception:

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/cursor.py" in execute
  56.                 params)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in __init__
  769.         self._query = self.parse()

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/sql2mongo/query.py" in parse
  864.                 raise exe from e

The above exception (FAILED SQL: INSERT INTO "terminal_rawrequest" ("content", "identifier") VALUES (%(0)s, %(1)s)
Params: ['2 + 2', 'heroku']
Version: 1.3.2) was the direct cause of the following exception:

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/cursor.py" in execute
  59.             raise db_exe from e

The above exception () was the direct cause of the following exception:

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
  97.         return handler(request, *args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  172.         return super().post(request, *args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  142.             return self.form_valid(form)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/edit.py" in form_valid
  125.         self.object = form.save()

File "/app/.heroku/python/lib/python3.6/site-packages/django/forms/models.py" in save
  458.             self.instance.save()

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in save_base
  779.                 force_update, using, update_fields,

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in _save_table
  870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in _do_insert
  908.                                using=using, raw=raw)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/query.py" in _insert
  1186.         return query.get_compiler(using=using).execute_sql(return_id)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1375.                 cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in execute
  99.             return super().execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in execute
  67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute_with_wrappers
  76.         return executor(sql, params, many, context)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/utils.py" in __exit__
  89.                 raise dj_exc_value.with_traceback(traceback) from exc_value

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/djongo/cursor.py" in execute
  59.             raise db_exe from e

Exception Type: DatabaseError at /
Exception Value:

Solution

  • As it turns out, I forgot to add sqlparse to my requirements.txt and, therefore, heroku was unable to run Djongo's parsing of SQL into noSQL. Based on this issue it seems like version 0.2.4 is the most stable version to use.

    requirements.txt

    django==2.2.12
    djongo==1.3.2
    gunicorn==19.9.0
    django-heroku==0.3.1
    django-crispy-forms==1.9.0
    dnspython==1.16.0
    sqlparse==0.2.4