django数据库读写分离

django之多数据库

一、多数据库-读写分离

由于一个django项目可能为了提高性能,会设置多个数据库,所以我们可以使用官方文档去学习如何设置

模型和数据库 - 多数据库 - 《Django v4.0 中文文档》 - 书栈网 · BookStack

1.在settings中配置数据库

DATABASES = {
    # pg数据库
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'Test_DB',
        'USER': 'postgres',
        'PASSWORD': '123456',
        'HOST': '127.0.0.7',
        'PORT': 5432
    },
    # mysql数据库
    'users': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test_mysql',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST':'127.0.0.7',
        'PORT':3306
    }
}

2.在app应用下的models中编写

class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

3.数据库迁移命令

#这个时候,因为现在是多个数据库,所以可以针对不同的数据库进行迁移

# 默认数据库 default - postgresql - shell
 python manage.py makemigrations
 python manage.py migrate


# users数据库 - mysql - shell
python manage.py migrate --database=users

4.编写分库方法

1. 方法1 - 使用using

from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
    # 方式一
    # 读数据 - users -msyql
    res = models.User.objects.using('users').all().first()
    # 写数据 - default -postgresql
    models.User.objects.create(name=res.name,age=res.age)
    return HttpResponse('index')

2. 方法2 - 编写类

# from django.db.models.options import  Options -- 查询字段
class DatabaseRouter(object):

    def db_for_read(self, model, **hints):
        print(model._meta.app_label)  # app01 有了这个可以分app判断 - 写逻辑
        print(model._meta.model_name)  # user 有着这里可以table判断 - 写逻辑

        return 'users'

    def db_for_write(self, model, **hints):
        print(model._meta.app_label)  # app01
        print(model._meta.app_label)  # user

        return 'default'

3. 在settings中注册

# 配置数据库
DATABASE_ROUTERS  = ['utils.database_selector.DatabaseRouter']
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.

def index(request):
    # 方式一 - using
    # 读数据 - users -msyql
    # res = models.User.objects.using('users').all().first()
    # 写数据 - default -postgresql
    # models.User.objects.create(name=res.name,age=res.age)

    # 方式二 - 类
    res2 = models.User.objects.all().first()
    print(res2)
    models.User.objects.create(name=res2.name, age=res2.age)

    return HttpResponse('index')

二、分库-app划分

1. 事前准备

首先,将数据库中的表删除

其次,将migrations 下的日志信息删除

最后,创建第二个app 为 app02

2. 在两个app应用中创建不同表

app01

# app01
from django.db import models

# Create your models here.

class UserPg(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

app02

# app02
from django.db import models

# Create your models here.
class UserMysql(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

3. 数据迁移 - 分库(app<---->数据库)

# 数据迁移日志
python manage.py makemigrations

# app01 下 迁移到 default - postgresql 数据库
python manage.py migrate app01 --database=default

# app02 下 迁移到 users - mysql 数据库
python manage.py migrate app02 --database=users

4. 注意事项

1.app 分库后,直接操作会报数据找不到

2.app分库后,需要使用 多数据库 - 读写分离的两种方式去配置

from django.shortcuts import render,HttpResponse
def index(request):
    # 方式一
    # 读数据 - users -msyql
    # res = models.User.objects.using('users').all().first()
    # 写数据 - default -postgresql
    # models.User.objects.create(name=res.name,age=res.age)

    # 方式二 - 类
    # res2 = models.User.objects.all().first()
    # print(res2)
    # models.User.objects.create(name=res2.name, age=res2.age)

    # 方式三 - app分库
    from app01 import models as m1
    from app02 import models as m2
    res3 = m1.UserPg.objects.all()
    print(res3)
    res4 = m2.UserMysql.objects.all()
    print(res4)

    return HttpResponse('index')

5. 具体解决

# from django.db.models.options import  Options -- 查询字段
class DatabaseRouter(object):

    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'app01':
        	return 'default'
        if model._meta.app_label == 'app02':
        	return 'users'

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'app01':
        	return 'default'
        if model._meta.app_label == 'app02':
        	return 'users'

三、分库-单app

(同一app中,不同表放在不同库中)**

1. 编写类 - allow_migrate

class DatabaseRouter(object):

    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'app02':
            return 'default'
        if model._meta.app_label == 'app03':
            return 'users'

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'app02':
            return 'default'
        if model._meta.app_label == 'app03':
            return 'users'

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if db == 'default':
            if model_name in ['UserInfoPg']:
                return True  # 返回true 执行数据迁移命令时 生成到数据库中
            else:
                return False # 返回False 执行数据迁移命令时 不生成到数据库中
        if db == 'users':
            if model_name in ['UserInfoMysql']:
                return True  # 返回true 执行数据迁移命令时 
            else:
                return False

2. 数据迁移

# 数据迁移日志
python manage.py makemigrations

# app01 下 迁移到 default - postgresql 数据库
python manage.py migrate app01 --database=default

# app02 下 迁移到 users - mysql 数据库
python manage.py migrate app02 --database=users

总结

1.分库 - 读写分离 - 多app - 单app

# settings 中配置
# DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']
class DatabaseRouter(object):
    """
       A router to control all database operations on models in the
       auth and contenttypes applications.
       """
    route_app_labels = {'auth', 'contenttypes'}

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth and contenttypes models go to auth_db.
        """
        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.
        """
        if app_label in self.route_app_labels:
            return db == 'auth_db'
        return None

2.注意事项

首先,表之间有关联的,应该在同一个库中

其次,分库可以根据需要,把关联的表分在同一个app中

然后,多数据库可以根据业务将不同的app下不同表分在不同库中,需要编写一个类。

最后,read / write 是库的orm操作 , migrate 是 数据迁移操作。

posted @   派森的猫  阅读(214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示