6.4 KiB
6.4 KiB
dealerhub · 经销商 SaaS — 阶段完成报告
详细计划见
PLAN.md;本文档是阶段 0 + 阶段 1 的 执行结果。
✅ 阶段 0(骨架 + 异步链路打通)
- ✅ Django 5.2 + DRF 3.17 + adrf 0.1.14 + Granian 2.8.2 + psycopg 3.2 + django-environ
- ✅ 完整 settings 分层:
config/settings/{base,dev,prod,test}.py - ✅
config/asgi.py(Granian 加载入口)+config/wsgi.py - ✅
pytest.ini+conftest.py+tests/(9 个测试全通过) - ✅ 数据库迁移:
core/catalog两个 app 的初始 migration 已落库
✅ 阶段 1(多租户预留 + 商品中心 CRUD)
- ✅ 多租户中间件
TenantMiddleware(基于X-Tenant-Idheader) - ✅ 抽象基类
TenantScopedModel:自动tenant_id/org_id/ext_data/source_channel/is_deleted/审计字段 - ✅
Org模型(多组织预留,org_path层级路径) - ✅ 商品中心 4 个 ViewSet(分类/品牌/单位/商品)+ DRF async 分页
- ✅ JWT 鉴权(SimpleJWT)+ admin 路径 + ping 路径公开
- ✅
acreate重写自动注入tenant/created_by/updated_by
✅ 关键技术问题与解法(实战踩坑)
adrf.routers没有Router类 → 改用from adrf.routers import DefaultRouter- DjangoFilterBackend 与 async view 不兼容(filter_queryset 同步调用 queryset.model,触发未 await 协程) → 自写 async 分页 + 简单 search
- DRF 默认 PageNumberPagination 同步 → 自写
StandardAsyncPagination(兼容传 coroutine) - 同步 ORM 在 async view 里需要 sync_to_async → 但直接写 ORM 调用(adrf 0.1.14 会自动 wrap)
asave()在 adrf 0.1.14 是必须的 → 抽象基类AsyncModelSerializer提供asave/acreate- create 时 tenant_id NOT NULL 约束 → 重写
acreate自动注入 tenant/org/user - pytest 的 AsyncClient + adrf view 触发 AsyncToSync RuntimeError → 改用同步 APIClient(Django 自动 wrap async view)
- pytest 设置
DJANGO_SECRET_KEY太短导致 JWT warning → 强制 ≥32 字符 - ping 路径被全局
IsAuthenticated拦截 → 在路由处覆盖@authentication_classes([]) @permission_classes([AllowAny])
✅ 验证证据
1. Django check 通过
$ python manage.py check
System check identified no issues (0 silenced).
2. 9/9 测试通过
$ python -m pytest tests/ -p no:cacheprovider
......... [100%]
9 passed, 21 warnings in 0.38s
3. 端到端同步验证脚本
[setup] tenant=default user=alice token-len=228
[ping] 200 body={"ok":true,"service":"dealerhub",...,"granian":"2.8.2"}}
[catalog/list] 200 body={"count":0,"next":null,"previous":null,"results":[]}
[catalog/create] 201 body={"id":1,"code":"P001","name":"...","status":"active",...}
[catalog/search] 200 body={"count":1,"next":null,"previous":null,"results":[{...}]}
📁 当前文件结构
dealerhub/
├── PLAN.md # 总体实施计划(5 个阶段)
├── README.md # 快速开始
├── PROGRESS.md # 本文件
└── backend/
├── manage.py
├── requirements.in
├── pytest.ini
├── conftest.py
├── .env
├── .gitignore
├── config/
│ ├── __init__.py
│ ├── settings/
│ │ ├── __init__.py
│ │ ├── base.py # 共享
│ │ ├── dev.py # SQLite + DEBUG
│ │ ├── prod.py # PostgreSQL + 安全
│ │ └── test.py # 内存 SQLite
│ ├── asgi.py # Granian 加载入口
│ ├── wsgi.py
│ └── urls.py # 根路由 + ping
├── apps/
│ ├── core/
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── base_models.py # TenantScopedModel 抽象基类
│ │ ├── middleware.py # TenantMiddleware
│ │ ├── models.py # Tenant/Org/AuditLog
│ │ ├── serializers.py # AsyncModelSerializer 基类
│ │ ├── views.py
│ │ ├── urls.py
│ │ └── management/commands/seed_initial_data.py
│ └── catalog/
│ ├── __init__.py
│ ├── apps.py
│ ├── models.py # Category/Brand/Unit/Product
│ ├── serializers.py
│ ├── views.py # async ViewSets + 异步分页 + tenant 注入
│ └── urls.py
├── tests/
│ ├── test_ping.py # 1 测试
│ ├── test_catalog.py # 6 测试
│ └── test_tenant.py # 2 测试
├── infra/
│ ├── docker/
│ │ ├── Dockerfile.backend
│ │ └── docker-compose.yml
│ └── scripts/
│ ├── run_dev.sh
│ └── run_prod_granian.sh
└── verify_sync.py # 端到端冒烟脚本
🚀 启动命令
本地开发
cd C:\Users\12914\Desktop\gj\dealerhub\backend
sh infra/scripts/run_dev.sh
# 或:
DJANGO_SETTINGS_MODULE=config.settings.dev granian config.asgi:application \
--interface asgi --host 0.0.0.0 --port 8000 --reload
Docker
cd C:\Users\12914\Desktop\gj\dealerhub
cd backend/infra/docker
DJANGO_SECRET_KEY=xxx POSTGRES_PASSWORD=yyy docker compose up -d
运行测试
cd C:\Users\12914\Desktop\gj\dealerhub\backend
DJANGO_SETTINGS_MODULE=config.settings.test \
DJANGO_SECRET_KEY="this-is-a-long-secret-key-for-jwt-tests-min-32-chars-OK" \
python -m pytest tests/ -p no:cacheprovider
⏭️ 下一步(阶段 2)
按 PLAN.md 推进:
apps/inventory:仓库 + 库存 + 批次 + 库存流水日志apps/purchase:采购订单/进货单/付款/退货apps/sales:销售订单/销售单/收款/退货apps/partner:客户/供应商/联系人/价格等级apps/finance:应收/应付/对账单core.workflow.StateMachine:单据状态机服务化- 库存原子服务(杜绝并发错票)
每一层都有 pytest 集成测试 + 端到端冒烟验证,结果会追加到本文件。
当前阶段: 阶段 1 完成(基础 + 多租户预留 + 商品 CRUD) 下一步: 阶段 2(进销存主线业务),预计 10–15 天开发量