【问题标题】:Django MySQL Error (1146, "Table 'db_name.django_content_type' doesn't exist")Django MySQL 错误(1146,“表 'db_name.django_content_type' 不存在”)
【发布时间】:2017-10-10 20:19:16
【问题描述】:

我收到了错误

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

在尝试使用我第一次在生产服务器上部署的新数据库对 django 项目进行初始迁移时。

我怀疑问题可能是因为其中一个应用程序的目录中充满了来自 SQLite3 开发环境的旧迁移;我清除了这些,但没有帮助。我还搜索并找到了对多个数据库有问题的人的引用,但我只有一个。

python 3.5.4 上的 Django 版本是 1.11.6,mysqlclient 1.3.12

【问题讨论】:

  • 在应用应用迁移之前您是否先运行python manage.py migrate?
  • 是的。同样的错误。
  • 您是否在代码中的任何地方调用 ContentType.objects 管理器,在构建数据库之前可能会调用它?我目前正面临这个问题,需要一种方法来检查数据库表是否已构建,然后才能查找任何 ContentTypes
  • 好点。我不是,但我会看看我的第三方模块是否有。
  • 完整的堆栈跟踪可能会让您了解有问题的调用可能来自哪里

标签: mysql django


【解决方案1】:

一些注意事项:

  • 您是否在代码中的任何地方调用 ContentType.objects 管理器,在构建数据库之前可能会调用这些管理器?
  • 我目前正面临这个问题,需要一种方法来检查数据库表是否已构建,然后才能查找任何 ContentTypes

我最终创建了一个方法来检查表以查看它是否已创建,不确定它是否也会帮助您:

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

至于迁移,我的理解是它们应该始终属于您的版本控制存储库,但是您可以根据需要压缩或编辑,甚至重建它们,这个链接可以帮助我解决一些迁移问题: Reset Migrations

【讨论】:

  • 谢谢,这比我的临时解决方案要干净得多,即捕获并忽略 DatabaseError
  • 关于迁移,我目前正在做的是第一次部署应用程序。所以我真的看不出开发中的几十个小增量迁移有什么价值。我更喜欢在新环境中生成一组干净的迁移。不过,我想这在我将来推出更改时不会起作用。
【解决方案2】:

回答我自己的问题:

UMDA 的评论是正确的。我有一些用于查看 content_types 的 django-import-export 模块的初始化代码,显然,自从我编写该应用程序以来,我从未在新环境中从头开始部署该应用程序。

经验教训/解决方案:

  • 会将有问题的代码包装在异常块中,因为我应该 在新环境中部署时仅出现一次此异常

  • 更定期地在新环境中测试干净的部署。

    • (编辑添加)考虑您的migrations目录是否属于.gitignore。出于我的目的,他们这样做了。

(stackoverflow 礼仪相对较新 - 我如何相信 UMDA 的评论让我走上了正轨?)

【讨论】:

    【解决方案3】:

    我在尝试创建通用 ModelView 时遇到了同样的问题(其中模型名称将作为变量在 urls.py 中传递)。我以一种愚蠢的方式处理这个问题:

    坏主意:返回基于类的通用视图的函数

    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"),
    ]
    

    无论如何。让我们不要停留在过去。

    这可以通过正确切换到基于类的视图来解决,而不是上面概述的任何地狱混合,因为(根据this SO post)基于类的视图直到请求时才会实例化。

    更好的主意:实际的基于类的通用视图

    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"),
    ]
    

    愿你犯新的更好的错误。

    【讨论】:

      【解决方案4】:

      加入,因为也许这个选项在某些情况下会更有吸引力。

      项目的大部分导入通常从您的urls.py 级联下来。我通常做的是将 urls.py 导入包装在 try/except 语句中,并且仅在所有导入成功时才创建路由。

      这样做的目的是仅在导入模块的情况下创建项目/应用程序的路由。如果由于表尚不存在而出现错误,则会将其忽略,并完成迁移。希望在下一次运行中,您的导入不会出错,一切都会顺利进行。但如果你这样做了,很容易被发现,因为你不会有任何 URL。此外,在这些情况下,我通常会添加一个错误日志来指导我解决问题。

      简化版如下所示:

      # 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
      

      现在,也许您可​​以将 Omar 的答案结合起来,以获得更明智、更少包罗万象的解决方案。

      【讨论】:

        猜你喜欢
        • 2016-06-14
        • 1970-01-01
        • 1970-01-01
        • 2015-06-01
        • 2017-05-30
        • 1970-01-01
        • 2013-10-20
        • 1970-01-01
        • 2014-05-15
        相关资源
        最近更新 更多