You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django测试时AppConfig.ready()先于迁移执行致表不存在错误

解决Django AppConfig.ready()测试时表不存在的问题

问题根源

执行manage.py test时,Django初始化测试环境的流程中,AppConfig.ready()会在数据库迁移前触发,此时news_newstype表还未创建,直接执行数据库查询就会抛出OperationalError。

可行解决方案

方案1:延迟数据查询,按需加载

不在ready()里提前执行查询并赋值,而是改成动态获取逻辑,在生成路由正则时才触发查询:

修改AppConfig代码:

class NewsConfig(AppConfig):
    name = "apps.news"
    verbose_name = "News"

    @property
    def news_type_names(self):
        NewsType = self.models.get("newstype")
        return NewsType.objects.values_list("name", flat=True)

调整urls.py中的路由生成逻辑:

from django.apps import apps

news_config = apps.get_app_config('news')
news_type_names_regex = generate_regex(news_config.news_type_names)
router = DefaultRouter()
router.register(r'news/' + news_type_names_regex, NewsModelViewSet, basename='news')

查询操作会延迟到路由生成时执行,而测试环境在运行测试前会完成数据库迁移,此时表已存在,不会触发报错。

方案2:在ready()中检查表是否存在

通过Django数据库连接工具,判断目标表存在后再执行查询:

from django.db import connection

class NewsConfig(AppConfig):
    name = "apps.news"
    verbose_name = "News"

    def ready(self):
        NewsType = self.models.get("newstype")
        # 检查目标表是否已创建
        with connection.cursor() as cursor:
            table_exists = connection.introspection.table_exists(cursor, NewsType._meta.db_table)
            if table_exists:
                NewsType.names = NewsType.objects.values_list("name", flat=True)
            else:
                # 未迁移或测试环境下设置默认值,避免后续路由生成报错
                NewsType.names = []

方案3:判断是否为测试环境

在项目settings.py中添加测试环境标识:

# settings.py
import sys
TESTING = 'test' in sys.argv

然后在AppConfig.ready()中跳过测试环境的查询操作:

from django.conf import settings

class NewsConfig(AppConfig):
    name = "apps.news"
    verbose_name = "News"

    def ready(self):
        NewsType = self.models.get("newstype")
        if not settings.TESTING:
            NewsType.names = NewsType.objects.values_list("name", flat=True)
        else:
            NewsType.names = []

注意事项

  • 若使用Django Channels,优先选择方案1,按需加载的逻辑不会影响ASGI应用启动,也无需依赖环境判断。
  • 所有方案都要保证news_type_names_regex生成时NewsType.names有合法值(如空列表对应默认正则),避免路由注册失败。

内容的提问来源于stack exchange,提问作者CurlyError

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 15:35:12