简体   繁体   中英

Django MySQL Error (1146, "Table 'db_name.django_content_type' doesn't exist")

I am getting the error

django.db.utils.ProgrammingError: (1146, "Table 'db_name.django_content_type' doesn't exist")

when trying to do the initial migration for a django project with a new database that I'm deploying on the production server for the first time.

I suspected the problem might be because one of the the apps had a directory full of old migrations from a SQLite3 development environment; I cleared those out but it didn't help. I also searched and found references to people having the problem with multiple databases, but I only have one.

Django version is 1.11.6 on python 3.5.4, mysqlclient 1.3.12

Some considerations:

  • Are you calling ContentType.objects manager anywhere in your code that may be called before the db has been built?
  • I am currently facing this issue and need a way to check the db table has been built before I can look up any ContentTypes

I ended up creating a method to check the tables to see if it had been created, not sure if it will also help you:

def get_content_type(cls):
    from django.contrib.contenttypes.models import ContentType
    from django.db import connection

    if 'django_content_type' in connection.introspection.table_names():
        return ContentType.objects.get_for_model(cls)
    else:
        return None

As for migrations, my understanding is that they should always belong in your version control repo, however you can squash, or edit as required, or even rebuild them, this linked helps me with some migrations problems: Reset Migrations

Answering my own question:

UMDA's comment was right. I have some initialization code for the django-import-export module that looks at content_types, and evidently I have never deployed the app from scratch in a new environment since I wrote it.

Lessons learned / solution:

  • will wrap the offending code in an exception block, since I should only have this exception once when deploying in a new environment

  • test clean deployments in a new environment more regularly.

    • (edit to add) consider whether your migrations directories belong in .gitignore . For my purposes they do.

(Relatively new to stackoverflow etiquette - how do I credit UMDA's comment for putting me on the right track?)

I had the same issue when trying to create a generic ModelView (where the model name would be passed as a variable in urls.py ). I was handling this in a kind of silly way:

Bad idea: a function that returns a generic class-based view

views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.views.generic.edit import DeleteView


def get_generic_delete_view(model_name):
     model_type = ContentType.objects.get(app_label='myapp', model=model_name)

     class _GenericDelete(LoginRequiredMixin, DeleteView):
         model = model_type.model_class()
         template_name = "confirm_delete.html"

     return _GenericDelete.as_view()

urls.py

from django.urls import path, include

from my_app import views

urlpatterns = [
    path("mymodels/<name>/delete/", views.get_generic_delete_view("MyModel"),
]

Anyway. Let's not dwell in the past.

This was fixable by properly switching to a class-based view, instead of whatever infernal hybrid is outlined above, since (according to this SO post ) a class-based view isn't instantiated until request-time.

Better idea: actual generic class-based view

views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.views.generic.edit import DeleteView

class GenericDelete(LoginRequiredMixin, DeleteView):
    template_name = "confirm_delete.html"

    def __init__(self, **kwargs):
        model = kwargs.pop("model")
        model_type = ContentType.objects.get(app_label='myapp', model=model)
        self.model = model_type.model_class()
        super().__init__()

urls.py

from django.urls import path, include

from my_app import views

urlpatterns = [
    path("mymodels/<name>/delete/", views.GenericDelete.as_view(model="MyModel"),
]

May you make new and better mistakes.

Chipping in because maybe this option will appeal better in some scenarios.

Most of the project's imports usually cascade down from your urls.py . What I usually do, is wrap the urls.py imports in a try/except statement and only create the routes if all imports were successful.

What this accomplishes is to create your project's / app's routes only if the modules were imported. If there is an error because the tables do not yet exist, it will be ignored, and the migrations will be done. In the next run, hopefully, you will have no errors in your imports and everything will run smoothly. But if you do, it's easy to spot because you won't have any URLs. Also, I usually add an error log to guide me through the issue in those cases.

A simplified version would look like this:

# Workaround to avoid programming errors on greenfield migrations
register_routes = True
try:
    from myapp.views import CoolViewSet
    # More imports...
except Exception as e:
    register_routes = False
    logger.error("Avoiding creation of routes. Error on import: {}".format(e))

if register_routes:
    # Add yout url paterns here

Now, maybe you can combine Omar's answer for a more sensible, less catch-all solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM