Django 工程结构以及利用Git分支进行生产环境切换

一个良好的工程结构不仅在开发时查找文件非常便利,同时也能够对开发的分层和模块儿化提供很多的帮助.

1. 常规的工程结构

在我们使用django-admin startproject project_name以及django-admin startapp app_name之后, Django会给我们提供一个最基本的工程目录结构:

那么当app的数量非常多的时候,其实很难的管理,所以需要对app-package进行统一的管理

2. 管理app

新建一个package, 命名为apps,在PyCharm中右键该package, 选择Mark Directory as, 选择Sources root, 并且将我们创建的app丢到apps这个包里面,修改settings.py的配置:

1
2
3
4
5
6
# settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 添加:
import sys
sys.path.insert(0, os.path.join(BASE_DIR, "apps"))

当我们的项目中如果出现了很多个app,并且属于不同的应用范畴时,那么继续新建package, 将不同的app-package丢进去,并且执行和上面相同的操作:

3. 管理settings.py配置文件

在日常的开发中,通常会有3个开发环境: 本地-测试-生产, 那么不同的开发环境对应不同的配置文件就显得非常重要了.
这里将settings.py进行模块儿化并拆分配置文件:

将其拆分为base, local, test, prod, 其中base.py写入通用的配置,比如BASE_DIR等信息.其余的文件分别对应本地-测试-生产环境的配置.
首先配置本地开发环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# local.py

from .base import *

DEBUG = True

INSTALLED_APPS += [
"app_01"
]

SECRET_KEY = '复制base.py中的SECRET_KEY'

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "demo",
"HOST": "localhost",
"PORT": 3306,
"USER": "root",
"PASSWORD": "",
"TEST": {
"charset": "utf8",
"COLLATION": "utf8_general_ci"
}
}
}

主要是对app的添加以及数据库,Redis等相关配置的区别,配置完成后需要对manage.py进行修改, 将settings配置文件指向local.py

1
2
3
4
5
6
7
# manage.py
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings.local")

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)

同样地,需要对wsgi.py中的settings进行相应的修改
因为我们将settings.py这个文件拆分成了一个package,那么工程下的BASE_DIR发生了某些变化,此时不再指向原有的工程目录,而是settings这个模块,
所以需要对其进行修改:

1
2
3
4
5
# 原有的BASE_DIR
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 修改
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

如果使用PyCharm进行开发和调试的话,需要对该工程的IDE配置做一些修改:

那么在不同的开发分支中,修改manage.py文件,使其指向对应的配置文件即可.

1
2
3
branch master --> local.py
branch test --> test.py
branch prod --> prod.py

4. 利用Git分支名称进行开发,测试以及生产环境的切换

在上面的文件拆分中,我们需要在不同的分支对manage.py以及wsgi.py文件中的DJANGO_SETTINGS_MODULE进行修改,使其指向不同的环境,有一些麻烦.
通过GitPython这个第三方库我们可以获取到当前Git分支的名称,那么就可以使用分支名称作为settings配置文件的代替物.
首先安装GitPython:

1
pip install GitPython

简单使用:

1
2
3
4
from git import Repo

repo = Repo(".git文件所在文件路径")
repo.active_branch.name # 获取当前分支名称

GitPython可以利用Python来完成Git所有能做的事情,但是在配置文件拆分中,我们只需要获取当前分支名称即可.更加具体的使用,见官方文档即可.
那么在有了GitPython驱动之后,我们就可以在base.py中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from git import Repo


def get_branch_name():
# 获取当前git分支名称
repo = Repo(os.path.dirname(BASE_DIR))
branch_name = repo.active_branch.name
return branch_name


def get_settings_name_on_branch_name(branch_name):
# 根据当前分支名称,取得所需要的配置文件名称.test分支指向test.py, prod分支指向prod.py
if branch_name in ["test", "prod"]:
return branch_name
else:
return "local"


def get_name():
branch_name = get_branch_name()
return get_settings_name_on_branch_name(branch_name)


def django_environ_setup():
# 对于一些特殊的文件需要使用到django的model或者其它模块儿,进行django.setup操作.
import os
import django
settings_name = get_name()
os.environ.update({"DJANGO_SETTINGS_MODULE": "BaiMiYouXuan.settings.{}".format(settings_name)})
django.setup()

那么在wsgi.py以及manage.py我们就可以这样使用:

  • manage.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
import os
import sys

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(BASE_DIR)

from BaiMiYouXuan.settings.base import get_name
name = get_name()


if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BaiMiYouXuan.settings.{}".format(name))

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
  • wsgi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
import sys

from django.core.wsgi import get_wsgi_application

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)

from BaiMiYouXuan.settings.base import get_name
name = get_name()


os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BaiMiYouXuan.settings.{}".format(name))

application = get_wsgi_application()

这样一来我们只需要关注于base, test, prod以及local这几个文件中的配置项,对于哪一个生产环境使用哪一个配置文件,由代码自动的获取.