Skip to main content

Django Read-Write Router

PyPI Repository

Django 读写分离 / Read-Write Separation 数据库路由器。主从复制场景下,写走主库、读走从库,支持事务感知与一致性哈希路由。

如果你在用 Django + PostgreSQL/MySQL 主从复制,需要把读请求分流到从库以减轻主库压力,或遇到「读己之写」不可见、复制滞后导致的数据不一致问题,这个包可以帮你快速接入读写分离。

适用场景 / When to Use

  • 主从复制架构:主库负责写,从库负责读,降低主库负载
  • 读多写少业务:大量查询走从库,写操作集中主库
  • 复制滞后一致性:事务内读自动走主库(Read Your Writes)
  • 单调读:同一用户多次读走同一从库,避免「时光倒流」

Features

  • 基础读写分离:写走主库,读走从库
  • 事务感知路由: 事务内读自动走主库(读己之写)
  • 一致性哈希路由: 同一用户始终读同一从库(单调读)
  • 请求上下文追踪: 中间件自动管理请求上下文
  • 主库 QuerySet: 可强制指定查询走主库

Installation

pip install django-rw-router

Or with uv:

uv add django-rw-router

Quick Start

1. 配置数据库

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'user',
        'PASSWORD': 'password',
        'HOST': 'primary.db.example.com',
        'PORT': '5432',
    },
    'readonly': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'readonly_user',
        'PASSWORD': 'password',
        'HOST': 'replica.db.example.com',
        'PORT': '5432',
    },
}

2. 添加路由器

# settings.py
DATABASE_ROUTERS = [
    'django_rw_router.routers.TransactionPrimaryReplicaRouter',
]

3. 添加中间件(HashPrimaryReplicaRouter 必选)

# settings.py
MIDDLEWARE = [
    'django_rw_router.middleware.RequestContextMiddleware',
    # ... 其他中间件
]

Router Options

路由器 场景 一致性
PrimaryReplicaRouter 基础读写分离 最终一致
TransactionPrimaryReplicaRouter 写后读 Read Your Writes
HashPrimaryReplicaRouter 同一用户多次读 Monotonic Reads
PrimaryReplicaRouterWithCtx 追踪写操作上下文 -

PrimaryReplicaRouter

基础读写分离。写走主库,读在从库间随机分配。

DATABASE_ROUTERS = [
    'django_rw_router.routers.PrimaryReplicaRouter',
]

TransactionPrimaryReplicaRouter(推荐)

事务内读写均走主库,避免复制滞后导致的"读己之写"不可见。

DATABASE_ROUTERS = [
    'django_rw_router.routers.TransactionPrimaryReplicaRouter',
]

HashPrimaryReplicaRouter

基于 user_id 的一致性哈希,同一用户始终读同一从库,保证单调读。

DATABASE_ROUTERS = [
    'django_rw_router.routers.hash.HashPrimaryReplicaRouter',
]
# 需启用 RequestContextMiddleware 以注入 user_id

PrimaryReplicaRouterWithCtx

在基础路由器上增加写操作上下文追踪,供上层逻辑判断。

DATABASE_ROUTERS = [
    'django_rw_router.routers.PrimaryReplicaRouterWithCtx',
]

一致性场景 (DDIA)

场景 含义 推荐路由器
Read Your Writes 写入后立即读可见 TransactionPrimaryReplicaRouter
Monotonic Reads 同一用户不出现时光倒流 HashPrimaryReplicaRouter
Consistent Prefix 有序读取不出现乱序 HashPrimaryReplicaRouter
Eventual Consistency 接受复制滞后 PrimaryReplicaRouter

Configuration

数据库别名

# settings.py

# 读从库别名(单个或列表)
DJANGO_RW_ROUTER_READ_DBS = ['readonly', 'readonly2']

# 写主库别名
DJANGO_RW_ROUTER_WRITE_DB = 'default'

# 一致性哈希虚拟节点数(HashPrimaryReplicaRouter)
DJANGO_RW_ROUTER_HASH_VIRTUAL_NODES = 40

中间件配置

# settings.py

# 从 request 提取 user_id 的路径(支持嵌套,如 user.id)
DJANGO_RW_ROUTER_USER_ID_ATTR = 'user.id'

# 从 request 提取 request_id 的路径
DJANGO_RW_ROUTER_REQUEST_ID_ATTR = 'id'

QuerySet 配置

# settings.py

# 强制 PrimaryQuerySet 所有读走主库
DJANGO_RW_ROUTER_QUERYSET_USING_ENABLE = True

# 启用 @use_primary_db 装饰器
DJANGO_RW_ROUTER_METHOD_USING_ENABLE = True

Usage Examples

Basic Usage

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)

# Writes go to 'default', reads go to 'readonly'
book = Book.objects.create(title="Django Guide")  # Write to primary
books = Book.objects.all()  # Read from replica

Transaction-Aware Reads

from django.db import transaction

with transaction.atomic():
    book = Book.objects.create(title="New Book")
    # This read goes to PRIMARY (not replica) because we're in a transaction
    fresh_book = Book.objects.get(id=book.id)

Using PrimaryManager for Critical Queries

from django.db import models
from django_rw_router.managers import PrimaryManager

class ImportantModel(models.Model):
    objects = PrimaryManager()

# When DJANGO_RW_ROUTER_QUERYSET_USING_ENABLE=True,
# all reads through this manager go to primary
obj = ImportantModel.objects.first()

Manual Database Selection

You can always override the router:

# Force read from primary
obj = Book.objects.using('default').first()

# Force write to replica (not recommended)
book.save(using='readonly')

How It Works

  1. 写操作:始终路由到主库 (default)
  2. 读操作:
    • 事务外:路由到随机从库
    • 事务内:路由到主库(避免读己之写不可见)
  3. Hash 路由:user_id 哈希后稳定选中同一从库
  4. 上下文:中间件在请求开始时注入、结束时清理

Testing

# uv
uv run pytest -v

# pip
pip install -e ".[dev]"
pytest -v

测试覆盖 context、routers、managers、middleware,以及 DDIA 四种一致性场景。

Requirements

  • Python >= 3.8
  • Django >= 3.2
  • uhashring >= 2.1

常见搜索关键词

Django 读写分离、Django read write separation、Django database router、主从复制、primary replica、read replica、Django 主从、Django 从库读、Django 读写分离中间件

License

MIT License

Contributing

欢迎提交 Pull Request。

Metadata

Release files for django-rw-router 0.0.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-rw-router 0.0.4
File Size Uploaded Provenance Actions
django_rw_router-0.0.4.tar.gz 59.8 kB Without provenance Details for django_rw_router-0.0.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-rw-router 0.0.4
File Interpreter ABI Platform Actions
django_rw_router-0.0.4-py3-none-any.whl Python 3 none any Details for django_rw_router-0.0.4-py3-none-any.whl

Total release size: 73.9 kB

Release files / django_rw_router-0.0.4.tar.gz

Download URL django_rw_router-0.0.4.tar.gz
Size 59.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6ff77c85374983152a36751bc19351a4ea75afccfe49dc47b08c8b890848de24
BLAKE2b-256 checksum
How to use checksums
628d11155b117301af1e58717a00ada1496a523db14a3d4c589f56ac2a7563fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.2

Release files / django_rw_router-0.0.4-py3-none-any.whl

Download URL django_rw_router-0.0.4-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd4b6da0bf6ef35729d42ad96f382b77cbc0a34aad3568d8dfa0669fecb00708
BLAKE2b-256 checksum
How to use checksums
5e2634af3bf964fde5f5b25f84d8463d0fc6a0f7bcedaf6c8fda566833559bca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.2

Security for django-rw-router 0.0.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page