最近看着Django 3.2 LTS发布了,就想着啥时候把当前项目用的Django 2.2版本给升级下。结果一升级,发现项目直接无法启动了,界面上在报类似下面的错误:
django.core.exceptions.ImproperlyConfigured: Cannot import ‘myapp’. Check that ‘apps.myapp.apps.MyappConfig.name’ is correct.
我在写这个项目的时候,习惯把自己创建的app都放到了项目src下的apps目录下,一个app一个目录,要import也应该是import apps.myapp啊,这里的import myapp失败是个啥问题?难道是这个写法到Django 3.2已经不支持了?
问题在哪里?
查了下Django 3.2的release note,第一个就是”Automatic AppConfig discovery“的变更,看来加载app的部分确实是做了修改。
对比了下Django 2.2和Django 3.2的源码,django/apps/config.py的代码变更还不少,在2.2中,如果app下面没有配置default_app_config属性(我们的app很简单,都直接这么写的),则代码非常简单,直接用INSTALLED_APPS中配置的路径进行import即可。在3.2中,default_app_config属性被废除掉了,app的发现模块加了很多行,加了一堆代码去支持在app的config子类中通过配置default参数来指定默认的app_config,这个时候原来省事儿的方法就不好使了,代码里面要求app config子类中的name必须是可以import的,否则就会报错。
感觉这已经算是很breaking change了,但是看网上的说法就是:你原来正规点做就没问题,出问题了肯定是因为之前就没正规地写做过这个配置。(但是我们都是老实地用startapp创建的app啊)
正规做法
一般的做法,遵从文档的描述,应该把app目录下的apps.py中配置子类的name给写好,可直接进行import:
1 | class MyappConfig(AppConfig): |
这种写法对第三方专门用来复用的app倒是无所谓,如果是给一个项目下写的特定的app那就不太友好了,需要挨个改掉这个name,而且后期如果apps目录改个名字,这里的修改又要重新进行一次。
Hacky way
从源码的逻辑来看,恢复原来AppConfig discovery的方法其实还有,就是直接在配置子类中指定default类变量是False,这样代码的逻辑会和2.2版本时候差不多。
一种改法:
1 | class MyappConfig(AppConfig): |
还有一种改法更简单,但是需要慎用,因为我也没测试这个变更对Django内置的一些app会有什么影响:
1 | # 修改项目的settings.py加入以下的配置 |
观察下后续官方有啥变更吧。