django配置多个db
如下,配置两个数据库:
DATABASES = {
# 默认使用的数据库
# 没有选择其他数据库时,就使用默认的,不使用时,可以配置一个空字典(必须)
'default': {
'ENGINE': 'django.db.backends.postgresql',
"HOST": "xxxx",
"PORT": "xxx",
'USER': 'postgres_user',
'PASSWORD': 's3krit',
'NAME': 'app_data',
},
# users应用连接的数据库
'users': {
'ENGINE': 'django.db.backends.mysql',
"HOST": "xxx",
"PORT": 3306,
'USER': 'mysql_user',
'PASSWORD': 'priv4te',
'NAME': 'users_data',
}
}
迁移时,一次操作一个数据库:
# 仅操作默认的 default 数据库
python manage.py makemigrations [appname]
python manage.py migrate [appname]
# 操作users(别名)数据库
python manage.py makemigrations
python manage.py migrate --database=users
默认的数据库,不使用时,可以配置一个空字典,但必须得定义,如下:
DATABASES = {
'default': {},
'users': {
'ENGINE': 'django.db.backends.mysql',
"HOST": "xx",
"PORT": 3306,
'USER': 'mysql_user',
'PASSWORD': 'superS3cret',
'NAME': 'user_data',
},
'customers': {
'ENGINE': 'django.db.backends.mysql',
"HOST": "xxx",
"PORT": "3306",
'USER': 'mysql_cust',
'PASSWORD': 'veryPriv@ate',
'NAME': 'customer_data',
}
}
此时,必须定义模型类的数据库路由
数据库路由
在主应用下创建database_router.py,内部定义数据库路由类。
数据库路由是一个类,提供如下四个方法:
db_for_read(model, **hints),模型类对象的读取
db_for_write(model, **hints),模型类对象的写入
allow_relation(obj1, obj2, **hints),表关系
allow_migrate(db, app_label, model_name=None, **hints), 是否允许迁移
1. 安装数据库路由:
# settings.py
# 配置数据库 一主两从
DATABASES = {
'default': {},
'auth_db': {
'NAME': 'auth_db_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'swordfish',
},
'primary': {
'NAME': 'primary_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'spam',
},
'replica1': {
'NAME': 'replica1_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'eggs',
},
'replica2': {
'NAME': 'replica2_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'bacon',
},
}
# 配置 数据库路由
DATABASE_ROUTERS = ["project_name.database_router.AuthRouter", "xxx"]
# 按照顺序逐一查找
2. 定义数据库路由
# database_router.py
class AuthRouter:
"""
A router to control all database operations on models in the
auth and contenttypes applications.
"""
# 指定使用某db的应用
route_app_labels = {'auth', 'contenttypes'}
def db_for_read(self, model, **hints):
"""
Attempts to read auth and contenttypes models go to auth_db.
"""
# 判断模型类的元类中的app_label
if model._meta.app_label in self.route_app_labels:
return 'auth_db'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return 'auth_db'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth or contenttypes apps is
involved.
"""
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):
"""
Make sure the auth and contenttypes apps only appear in the
'auth_db' database.
app_label, 表示使用的数据库别名
"""
if app_label in self.route_app_labels:
# 允许迁移到auth_db
return db == 'auth_db'
# 不允许迁移
return None
# 其他的应用 操作主从数据库
import random
class PrimaryReplicaRouter:
def db_for_read(self, model, **hints):
"""
传入的模型类,每次读取时都会走这里
Reads go to a randomly-chosen replica.
"""
# 路由到一个随机的从节点
return random.choice(['replica1', 'replica2'])
def db_for_write(self, model, **hints):
"""
model, 传入的模型类,每次写入时都会走这里
Writes always go to primary.
"""
# 写入主库
return 'primary'
def allow_relation(self, obj1, obj2, **hints):
"""
Relations between objects are allowed if both objects are
in the primary/replica pool.
"""
db_set = {'primary', 'replica1', 'replica2'}
if obj1._state.db in db_set and obj2._state.db in db_set:
return True
return None
# 允许迁移
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
db,允许迁移的数据库,默认是‘default’
app_label, 应用的名字
model_name, 模型类的名字
model, 模型类
"""
# 允许迁移
return True
在配置文件中,加入如下:
DATABASE_ROUTERS = ['project_name.database_router.AuthRouter', 'project_name.database_router.PrimaryReplicaRouter']
还需为应用下的模型类,指定使用的数据库:
class User(models.Model):
...
class Meta:
db_table = "user"
managed = True # 托管模式
app_label = "users" # 通过users应用,使用指定的的db
# 迁移
python manage.py makemigratins users
python manage.py migrate users --database=auth_db
手动选择一个db
CRUD可以通过using(“xxx”)指定数据库,
优先级高于数据库路由
>>> # run on the 'default' database.
>>> Author.objects.all() # 默认查询default 数据库
>>> Author.objects.using('default').all()
>>> # run on the 'other' database.
>>> Author.objects.using('other').all()
# 保存到指定数据库
>>> my_object.save(using='users_db')
# 主键重复问题
>>> p = Person(name='Fred')
>>> p.save(using='firstDB') # 先保存到第一个db
>>> p.save(using='secondDB') # 再保存到第二个db,此时p是带有主键的,在写入第二个数据库时,会覆盖相同主键的数据,从而造成 原数据 的丢失。采用如下方式解决:
>>> p.pk = None # Clear the primary key.
>>> p.save(using='second') # 没有主键会被当成新对象,插入
或者采用强制插入的方式:
>>> p.save(using='second', force_insert=True)
# 保存与删除
>>> user_obj.save(using='new_users')
>>> user_obj.delete(using='legacy_users')
# 使用users_db 创建用户对象
>>> User.objects.db_manager('users_db').create_user(...)
# 判断用户权限
>> user = User.from_db("primary", "username", "jack")
>> user.has_perm("add_user") # 是否有增加用户的权限 _user是User模型类
>> user.has_perms(["add_user", "delete_user", "view_user", "change_user"]) # 增删改查权限