发布于2026-07-20 阅读(0)
扫一扫,手机访问
在Django 4中实现读写分离,核心是自定义一个DatabaseRouter类。这个类需要实现四个方法:db_for_read、db_for_write、allow_relation、allow_migrate。每个方法都必须返回字符串(数据库别名)或None,否则Django会报错。一个常见的坑是只实现了读写路由,却忘了allow_migrate——这会导致migrate命令报错,因为迁移默认只作用于default库,而路由拦截了但没明确放行。

DatabaseRouter 类具体来说,四个方法各有讲究:
db_for_read:建议按模型类判断。比如对于User、Order这类读多写少的模型,返回'sla ve';对于后台管理类模型,直接返回None(走默认库)。db_for_write:一般统一返回'default',除非你真有分库写入的需求。allow_relation:跨库外键在Django 4中不被支持。只要涉及不同数据库的两个模型实例,必须返回False;同库或包含default的组合才考虑返回True。allow_migrate:迁移应该只发生在default(主库)。所以,当db == 'default'且app_label在白名单内时,返回True;其余一律返回False或None。路由类写好了,还得在settings.py里注册。必须把router类路径加到DATABASE_ROUTERS列表里,否则Django完全不会调用它。注意,这个配置是列表,每个元素是字符串,比如'myapp.routers.MyRouter',不要加括号或实例化。
数据库配置本身要提前定义好,每个库的NAME、HOST、USER等字段不能遗漏。Django 4不再容忍HOST为空字符串,本地MySQL必须显式写'localhost'或'127.0.0.1'——二者行为不同,后者会绕过socket。
'default',这是Django内部硬编码依赖的别名,改了会导致admin、auth、session等模块异常。'sla ve'或'replica1',需确保settings.DATABASES字典里真实存在该key。django-environ,注意环境变量解析后仍要保证每个库的ENGINE值正确,比如'django.db.backends.mysql'不能拼错。光看代码没用,得实测。最直接的方法是在db_for_read里加print(f"READ from {model.__name__} → {db}"),然后执行一个MyModel.objects.all().first(),观察输出。但生产环境不能打日志,更可靠的是查数据库连接数或慢查询日志。
另一个常见陷阱:Django的QuerySet是惰性的,.filter()不触发查询,只有.first()、.list()、for obj in qs:才真正发SQL。如果你只写了qs = MyModel.objects.using('sla ve').all(),那其实是手动指定库,和router无关,属于绕过机制。
using()调用,只用普通ORM查询,再看日志或数据库监控。default),哪怕你在transaction.atomic()里调.all()——这是Django的安全策略,无法通过router改变。django-debug-toolbar时,SQL面板显示的数据库名才是最终依据,比代码推断更可信。select_related 和 prefetch_related 会出问题这两个API在多库下极易翻车。select_related生成JOIN,而跨库JOIN在MySQL/PostgreSQL中不合法,Django会静默降级为多次查询,但可能把本该走从库的关联表查到了主库上;prefetch_related默认也走主库,除非你显式传using='sla ve',但它不接受router动态决策。
根本原因是:Django的关联查询路由逻辑不经过你的DatabaseRouter,而是由QuerySet._db决定,而这个值在select_related构建时就被固化了。所以,不要指望router能自动分流关联查询。
select_related关联主库模型(如User.profile),改用两次独立查询加手动组装。prefetch_related若必须用,先.using('sla ve'),再链式调用,例如Book.objects.using('sla ve').prefetch_related('author')。get_queryset()中加.using('sla ve')是可行的,但要注意它无法改变已存在的select_related行为。读写分离不是开个开关就完事的事。router只管顶层查询入口,关联、事务、缓存、测试fixture都可能绕过它。越靠近数据层,越得盯着每一条SQL实际发给了谁。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8