Django + Heroku + MongoDB Atlas (Djongo) = DatabaseError 无异常

hue*_*a12 2 django heroku mongodb nosql djongo

问题的一行描述

每当我部署在 heroku 上的 django 应用程序尝试访问我的 MongoDB Atlas 集群以提交表单或检查管理员登录时,它都会抛出类似附加错误的内容。

额外的细节

此处可在 heroku 构建中重现错误

我认为这是错误与 heroku 如何与我的 MongoDB Atlas 集群交互有关,因为当我在本地运行构建时,我能够让应用程序成功读取并修改我的数据库中的不同记录。

我已经启用了从所有 IP 地址到我的 Atlas 集群的流量,从我的 Heroku 应用程序和配置变量中删除了默认的 Heroku PostrgreSQL 数据库,并将我自己的数据库 IP 存储为配置变量。

任何帮助将不胜感激。

Python脚本


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


Run Code Online (Sandbox Code Playgroud)

    # 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')

Run Code Online (Sandbox Code Playgroud)

    """
    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())

Run Code Online (Sandbox Code Playgroud)

追溯

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:
Run Code Online (Sandbox Code Playgroud)

hue*_*a12 6

事实证明,我忘记将 sqlparse 添加到我的 requirements.txt 中,因此,heroku 无法将 Djongo 的 SQL 解析运行到 noSQL 中。基于这个问题,0.2.4 版本似乎是最稳定的版本。

要求.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
Run Code Online (Sandbox Code Playgroud)