Skip to main content

Django database read-write separation router with transaction-aware and consistent hash routing support

Project description

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。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_rw_router-0.0.4.tar.gz (59.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_rw_router-0.0.4-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file django_rw_router-0.0.4.tar.gz.

File metadata

  • Download URL: django_rw_router-0.0.4.tar.gz
  • Upload date:
  • Size: 59.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for django_rw_router-0.0.4.tar.gz
Algorithm Hash digest
SHA256 6ff77c85374983152a36751bc19351a4ea75afccfe49dc47b08c8b890848de24
MD5 45cea958dfa782377479dad28da7f082
BLAKE2b-256 628d11155b117301af1e58717a00ada1496a523db14a3d4c589f56ac2a7563fb

See more details on using hashes here.

File details

Details for the file django_rw_router-0.0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for django_rw_router-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 fd4b6da0bf6ef35729d42ad96f382b77cbc0a34aad3568d8dfa0669fecb00708
MD5 99ebe94530d90ae369058a32a17aed11
BLAKE2b-256 5e2634af3bf964fde5f5b25f84d8463d0fc6a0f7bcedaf6c8fda566833559bca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page