Search code examples
pythondjangodjango-templatesdjango-tables2

Using Django-tables2 with class-based view and non-default database throws "NameError: name 'TypeError' is not defined"


I am trying to set up django-tables2 and followed the recommendations in their docs. However, if I call the view, it throws the error

File "/home/ubuntu/mysite/mysite_venv/lib/python3.8/site-packages/asgiref/local.py", line 94, in __del__
NameError: name 'TypeError' is not defined

Note: From what I could gather, this error message unfortunately also occurs in other contexts as the most upvoted thread deals with an Apache config problem. I would be glad to adjust the title for clarity once the issue has been grasped concisely.

Django-tables2 should access (read-only) a legacy MySQL database which I added behind the default SQLite database in settings.py (see further down).

My polls/models.py:

from django.db import models
import datetime
from django.db import models
from django.utils import timezone

...

class Dashboard(models.Model):
    host = models.CharField(db_column='Host', max_length=255, blank=True, null=True)
    title = models.TextField(db_column='Title', blank=True, null=True)
    operation = models.CharField(db_column='Operation', max_length=255, blank=True, null=True)
    performedat = models.DateTimeField(db_column='PerformedAt', blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'dashboard'

In case it's necessary, the underlying table in MySQL looks like this:

c.execute('''CREATE TABLE dashboard(
            id INT PRIMARY KEY AUTO_INCREMENT,
            Host VARCHAR(255),
            Title TEXT,
            Operation VARCHAR(255),
            PerformedAt DATETIME);''')

My polls/views.py:

from django.shortcuts import render
from django.views.generic.list import ListView
from .models import Dashboard
from django.http import HttpResponse

class DashboardListView(ListView):
    model = Dashboard
    template_name = 'polls/dashboard.html'

Note: I have made sure that dashboard.html does reside in mysite/polls/templates/polls.

My polls/urls.py:

from django.urls import path

from polls.views import DashboardListView, detail, accept, reject

urlpatterns = [
    # ex: /polls/
    path('', DashboardListView.as_view()),
    #ex: /polls/5/
    path('<int:question_id>/', detail, name='detail'),
    #ex: /polls/5/accept/
    path('<int:question_id>/accept/', accept, name='results'),
    # ex: /polls/5/deny/
    path('<int:question_id>/deny/', reject, name='reject'),
]

My polls/dbrouters.py:

from polls.models import Dashboard

class DashboardDBRouter:
    def db_for_read (self, model, **hints):
        if (model == Dashboard):
            # your model name as in settings.py/DATABASES
            return 'dashbaord'
        return None

My dashboard.html (just used the tutorial template):

{# polls/templates/polls/dashboard.html #}
{% load render_table from django_tables2 %}
<!doctype html>
<html>
    <head>
        <title>List of persons</title>
    </head>
    <body>
        {% render_table object_list %}
    </body>
</html>

My settings.py:

# Application definition

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_tables2',
]

DATABASE_ROUTERS = (
    'polls.dbrouters.DashboardDBRouter',
)

...

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',
            ],
        },
    },
]

...

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    },
    'dashboard': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'testdatabase',
        'USER': 'my_username',
        'PASSWORD': 'my_password',
        'HOST': 'my_host',
        'PORT': '3306'
    },
}

What I noticed is that if I open a shell with python manage.py shell and just call the manager via Dashboard.objects.all() I get

django.utils.connection.ConnectionDoesNotExist: The connection 'dashbaord' doesn't exist.

While if I call Dashboard.objects.all().using(‘dashboard’) it seems to work since I then get

<QuerySet [<Dashboard: Dashboard object (1)>]>

Is it possible that something is wrong with my router? I thought it should connect automatically if I understood this answer correctly.

My second guess: I don't have much experience with Django and class-based views yet, so this might be completely off, but I am confused that neither my model nor my view contain any statements that contain any return or str() statements although I have found contrary examples here and here.

I thought that this might be the issue because it could explain the error in the sense that the Python interpreter is destroyed before the process is completed because nothing is returned as was discussed here (unfortunately without a clear result).

I honestly don’t know where to go from here, any help is really appreciated.


Solution

  • There's a typo in your spelling of dashbaord (should be dashboard) in routers.py:

    django.utils.connection.ConnectionDoesNotExist: 
       The connection 'dashbaord' doesn't exist.
                      ^^^^^^^^^^^