Post

【Django】数据库

1.配置数据库

官方文档:

settings.py中的DATABASES指定项目使用的数据库。

1.1 SQLite

1
2
3
4
5
6
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

1.2 MySQL

支持版本:MySQL 5.6及以上

安装连接驱动:mysqlclient(推荐)

1
pip install mysqlclient

MySQL Connector/Python

1
pip install mysql-connector-python

设置文件:

1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_name',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': '192.168.0.1',
        'PORT': '3306'
    }
}

以上方法直接将密码暴露在设置文件中,如果把项目上传到GitHub则是不安全的。

更安全的方式是使用MySQL配置文件,这也是Django官方文档中推荐的方式:

1
2
3
4
5
6
7
8
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': os.path.join(BASE_DIR, 'my.ini'),
        },
    },
}

其中my.ini的内容如下:

1
2
3
4
5
6
7
[client]
host = 192.168.0.1
port = 3306
user = username
password = password
database = db_name
default-character-set = utf8

该文件可以放在任何地方,这里将其放在工程根目录下(注意路径中不能包含中文,否则MySQL会读取失败),并将其在.gitignore中排除,这样就保护了密码安全。

原理:OPTIONS指定了MySQL连接驱动(如mysqlclient)的连接参数read_default_file而不是host, user, password等,相当于将mysql -h 192.168.0.1 -u username -p password -D db_name改为mysql --defaults-file=/path/to/my.ini

2.多数据库

官方文档:https://docs.djangoproject.com/en/stable/topics/db/multi-db/

2.1 设置文件

DATABASES设置中增加一个数据库连接配置并自定义一个别名。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}

2.2 数据库路由器

数据库路由器是定义了db_for_read(), db_for_write(), allow_relation(), allow_migrate()四个方法的类,用于决定每个模型使用哪个数据库。

下面的示例定义了users数据库路由器:user应用的模型使用别名为users的数据库;其他情况返回None,表示该路由器不做决定,由后续路由器来决定。如果没有其他路由器则默认使用default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class UsersRouter:
    route_app_labels = {'user'}

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'users'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'users'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if obj1._meta.app_label in self.route_app_labels \
                or obj2._meta.app_label in self.route_app_labels:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if db == 'users':
            return app_label in self.route_app_labels
        return None

假设上面的类定义在{项目根目录}/mysite/routers.py中,则在设置文件中增加:

1
DATABASE_ROUTERS = ['mysite.routers.UsersRouter']

也可以在查询时指定使用的数据库:

1
u = User.objects.using('users').get(username='fred')

2.3 测试

TestCase类中增加类属性:

1
databases = {'default', 'users'}
This post is licensed under CC BY 4.0 by the author.