Files
DjangoAdmin_FastAPI_EleVue/CLAUDE.md
T
ClaudeandClaude 63bebedf05 feat(phase5): 解耦与收尾清理
- core/redis_client.py 移除 scheduler 耦合,lifespan 由 core/app.py 组合(Redis→调度器→Redis)
- main.py 改从 core.app 导入 create_app
- 删除 apps/、extensions/ 目录;utils 删除已迁移垫片与死代码 formatter.py
- 新增 deploy/(nginx、supervisor)、scripts/(init_db、seed)、logs/(结构化日志落盘)
- core/app.py 接入 core.logger setup_logging
- 更新 CLAUDE.md 反映 core/shared/modules 新结构

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 10:16:44 +08:00

9.3 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

DjangoAdmin FastAPI+EleVue is a backend admin framework built with FastAPI (Python), Vue2.x + ElementUI (frontend, separate repo), and MySQL. It provides RBAC-based user/role/menu management, dictionary/config management, and CMS-like modules (notices, ads, members, etc.). The UI language and code comments are in Chinese.

Running the Application

# Install dependencies
pip install -r requirements.txt

# Run dev server (default: 127.0.0.1:8031)
python main.py

# Run via uvicorn directly
uvicorn main:app --host 127.0.0.1 --port 8031

# Docker
docker-compose up --build

Requires MySQL and Redis running. Configure connection details in .env (see .env for all variables). The database table prefix is fastapi_ (set via DB_PREFIX).

No test suite, linter, or formatter configuration exists in this project.

Architecture

Request Flow

main.py -> apps.create_app() -> registers CORS, Redis, routers, middleware, exception handlers -> all routes go through login_required dependency (except /login and /captcha) -> permission_required decorator checks node-level RBAC per endpoint -> check_demo decorator blocks write operations in demo mode.

Layered Module Pattern

Each business module (e.g., level, position, dept, role, user, menu, notice, dicts, config, etc.) follows the same 4-file pattern under apps/:

  • views/{module}.py - FastAPI router with endpoint definitions. Uses @permission_required("sys:{module}:{action}") and @check_demo decorators. Returns R.ok()/R.failed(). Endpoints that accept a body declare a Pydantic form parameter (e.g., data: PositionForm) — FastAPI parses and validates the JSON automatically before the handler runs.
  • services/{module}.py - Business logic: queries, CRUD operations, Excel import/export. Uses db.query(Model) directly with SQLAlchemy. Reads query params via request.query_params; body params arrive as already-validated Pydantic models, so services access fields via data.field or data.model_dump() (no await request.json() in service bodies).
  • forms/{module}.py - Pydantic BaseModel validation classes. Fields use Field(...) for constraints (min_length, max_length, ge, le, gt). Custom validators use @field_validator('field') raising ValueError(msg). Uniqueness checks query db.query(Model).filter(...).first() inside validators.
  • models/{module}.py - SQLAlchemy ORM model inheriting base_model (provides id, create_user, create_time, update_user, update_time, is_delete) and base_db (provides save(), save_all(), delete()). Table name uses DB_PREFIX prefix.

Request Validation

Pydantic v2 is used for all request body validation. The pattern for an endpoint:

@router.post('/add')
@permission_required("sys:level:add")
@check_demo
async def add(request: Request, data: LevelForm):
    return await level.LevelAdd(request, data)

Validation errors are caught by a global RequestValidationError handler registered in core/app.py and converted to the standard response shape {"code": -1, "data": null, "msg": "field: message/..."} with HTTP 200. Services receive the validated Pydantic instance and use data.model_dump() (full dict), data.model_dump(exclude={'id'}) (for updates), or direct attribute access (data.id, data.status).

Key Directories

  • config/ - Configuration split into sub-modules: app.py (app settings, CORS, upload limits), database.py (DB connection, pool config, SQLALCHEMY_MYSQL_URL), redis.py, auth.py (JWT), captcha.py, email.py, sms.py. All loaded from .env via python-dotenv. config/__init__.py loads .env first, then re-exports everything.
  • core/ - Core infrastructure: database.py (engine/SessionLocal/_db_ctx/get_db_session()/commit_independently/Base), redis_client.py (get_redis()/redis_lifespan/redis_middleware), jwt.py (JWT create/parse/refresh/blacklist with HS256), password.py (bcrypt hashing with salt), response.py (R.ok()/R.failed()), exceptions.py (AuthorizationException/BusinessException), security.py (get_user_id/get_username), middleware.py (login_required/permission_required/check_demo/db_session_middleware/operation_log_middleware/register_cros), deps.py (DI), logger.py (structured logging), app.py (create_app factory + lifespan).
  • shared/ - Cross-module shared layer: enums.py (enum dicts), constants.py (PAGE_SIZE/DEFAULT_PASSWORD/SERIALIZE_EXCLUDE_FIELDS), pagination.py, base_model.py, base_db.py, base_repository.py (Generic repository base), base_service.py.
  • modules/ - Business modules, each a directory with router.py (may export multiple routers, e.g. dict_router + dict_item_router), schemas.py, service.py, repository.py, models.py. Module groups: auth/, system/ (user, role, menu, dept, position, level), dictionary/, configuration/, cms/ (item, item_cate, ad, ad_sort), member/, region/, link/, notice/, job/ (job + job_log + scheduler + job_executor), log/, upload/, index/.
  • routers/ - v1.py central route registration (imports routers from modules/), __init__.py mounts login (免认证) on app and v1 behind login_required.
  • utils/ - Remaining utilities that stay here: request (parse_batch_ids, like_escape, like_contains), captcha, file, ip/ip2region, ua, rich_text, perm_cache. R/password are re-exported from core via utils/__init__.py for back-compat.

Database Access

Database sessions are request-scoped via contextvars + Starlette middleware (core/middleware.py: db_session_middleware). Services call db = get_db_session() (from core.database) to get the current request's session. Models use self.save() / self.delete() from shared/base_db.py. The middleware auto-closes the session after each request (with rollback). Soft deletes via is_delete flag (0=active, 1=deleted).

Redis Access

Redis uses async client via core/redis_client.py. Connection pool created in redis_lifespan (composed with scheduler startup in core/app.py lifespan), injected per-request via redis_middleware into contextvars. Business code calls get_redis() to get the current request's async Redis client.

Authentication & Authorization

  • JWT tokens via core/jwt.py (HS256, configurable expiry via JWT_EXPIRE_MINUTES, secret via JWT_SALT env var). Token sent as Authorization: Bearer <token> header. Supports token refresh and blacklist (logout) via Redis.
  • login_required is a FastAPI Depends applied globally to the v1 router. On success, it sets request.state.user_id, request.state.username, request.state.realname.
  • permission_required is a per-endpoint decorator checking permission strings like "sys:level:list". User ID 1 (admin) bypasses all permission checks. It lazily queries modules.system.menu.service.get_permissions_list_sync.
  • check_demo is a per-endpoint decorator that returns R.failed("演示环境,暂无操作权限") when FASTAPI_DEMO=True. Apply it after @permission_required on all write endpoints (add, update, delete, status, import, export).

API Response Format

All endpoints return JSONResponse via R.ok() or R.failed():

{"code": 0, "data": ..., "msg": "操作成功", "ok": true}   // success
{"code": -1, "data": null, "msg": "错误信息", "ok": false}  // failure

R.ok() supports **kwargs for extra fields (e.g., R.ok(data=result, count=total) adds a count field).

Pagination Pattern

List endpoints read pageNo and pageSize from request.query_params, defaulting to page 1 and PAGE_SIZE (10). Services use SQLAlchemy .limit(limit).offset((page - 1) * limit).all() and return R.ok(data=result, count=count).

Delete Pattern

Single delete: DELETE /delete/{id} where id can be comma-separated (e.g., "1,2,3"). Batch delete: DELETE /batchDelete with JSON body [1, 2, 3], parsed via parse_batch_ids(request). Both use soft delete (set is_delete = 1).

Adding a New Module

  1. Create modules/{group}/{name}/models.py - model class inheriting base_model and base_db (from shared/), set __tablename__ = DB_PREFIX + "{name}"
  2. Create modules/{group}/{name}/schemas.py - Pydantic BaseModel validation classes with Field(...) constraints and @field_validator for custom checks
  3. Create modules/{group}/{name}/repository.py - subclass shared.base_repository.BaseRepository + module-level instance
  4. Create modules/{group}/{name}/service.py - CRUD service functions following the get_level_page/get_level_detail/add_level/update_level/delete_level/update_level_status pattern
  5. Create modules/{group}/{name}/router.py - APIRouter with endpoints, apply @permission_required and @check_demo on write endpoints
  6. Register the router in routers/v1.py - v1.include_router({name}_router, prefix="/{prefix}", tags=["标签"])

Key Dependencies

  • FastAPI 0.140.0, Uvicorn 0.51.0
  • SQLAlchemy 2.0.51 (declarative style with declarative_base(), not 2.0 mapped_column style)
  • PyMySQL 1.2.0, Redis 8.0.1 (async), PyJWT 2.13.0
  • Pydantic 2.13.4 (for request validation via BaseModel + Field + field_validator), openpyxl (for Excel import/export)
  • python-dotenv for .env loading, bcrypt for password hashing, Pillow for captcha generation