公司的django项目下中的一个app要进行一些单独的config。本来嘛,创建一个文件,python的HTML的js的都好,把要config的信息写进去,然后再到要用的地方读出来就行了,或者干脆丢到项目级别的settings.py里头。但我总觉得这两种做法都很不standard——只为了一个config信息创建一个文件太不划算,而这个配置信息只在App内部使用,不想放到项目级别下污染其他人的config。
难道django自己就没有进行App level配置的接口了么?
还真有。
每个用过django的人都应该见过下面几个文件:
它是我们在使用命令 startapp时自动就会为我们创建的文件。urls.py views.py models.py使用频率很高不用多说,admin.py与django自带的管理工具有关,tests.py见名知意,那剩下的apps.py是干嘛的?
这里是对于apps.py 的官方文档。下面是找到的一个翻译版本。
官方文档:https://docs.djangoproject.com/en/2.0/ref/applications/
翻译版本:https://www.jb51.net/article/133890.htm
粗读了一遍确定,这就是我想要的app level的配置接口。
那么如何使用呢?
首先在初始情况下,apps.py的内容是这样的:
# myApp/apps.py
from django.apps import AppConfig
class MyappConfig(AppConfig):
name = 'myApp'
那么第一步,是在这里添加入我自己的config:
# myApp/apps.py
from django.apps import AppConfig
class MyappConfig(AppConfig):
name = 'myApp'
version = '1.0.1'
然后就可以愉快地在myApp内部读取到version啦——才怪,会报错的好伐!
接下来要做一项重要的操作,在项目级别下的settings.py中,用我们新建的app level的配置,替换掉该项目的默认配置:
# settings.py - project level
INSTALLED_APPS = [
# 'myApp', # 原来的config。要被下面那条替换掉。
'myApp.apps.MyappConfig'
]
不能不加'myApp.apps.MyappConfig'。否则项目无法获取到新增的version 配置项
不能myApp 和'myApp.apps.MyappConfig'同时配置在INSTALLED_APPS里头。否则会报错 django.core.exceptions.ImproperlyConfigured: Application labels aren't unique
做好配置之后,就真的可以在App的其他地方读取了。比如下面的例子,我在views.py中获取到version:
# myApp/views.py
from django.apps import apps
MY_APP_VERSION = apps.get_app_config('myApp').version
def say_hello(request):
# return HttpResponse("Hello")
return HttpResponse(MY_APP_VERSION)
# urls.py:
urlpatterns = [
path('sayHello/', views.say_hello),
# ...
]
访问sayHello试一下:
基本功能就完成了。
其实还有很多不满意的地方,其中最重要的就是,我其实并不愿意将INSTALLED_APPS中原有的config替换掉。这样动作太大了,担心会有不可知的bug出现。更好的方案有待后续研究啦。
====== 20201103 更新
在同事的启发下找到了不修改INSTALLED_APPS的做法:
# myApp/apps.py
from django.apps import AppConfig
class MyappConfig(AppConfig):
name = 'myApp'
version = '1.01.01'
# myApp/views.py
from django.http import HttpResponse
from myApp.apps import MyappConfig
VERSION = MyappConfig.version
def say_hello(request):
return HttpResponse(VERSION)
也就是说,将apps.py当做一个单纯的配置文件来看待。
这样实际就不走django给我们预留的接口了,内心有点小失落,但也不失为一种办法嘛。