初始化文档
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# **Python 编码与开发规范**
|
||||
|
||||
Python 是一门极其灵活的动态语言,但“灵活”在大型团队协作中往往意味着“灾难”。本规范以 **PEP 8** 为基石,全面拥抱 **现代 Python (3.9+)** 的类型注解系统,并强制依赖自动化工具链来消除代码风格争议。
|
||||
|
||||
## **命名约定与基础风格**
|
||||
|
||||
**核心理念:代码是写给人看的,顺便交给机器执行。**
|
||||
|
||||
* **变量与函数(变量/方法):** 强制使用 snake\_case(下划线命名)。
|
||||
\# 推荐
|
||||
user\_account\_list \= \[\]
|
||||
|
||||
def fetch\_user\_data():
|
||||
...
|
||||
|
||||
* **类名(Classes):** 强制使用 PascalCase(大驼峰命名)。
|
||||
class PaymentService:
|
||||
...
|
||||
|
||||
class UserNotFoundError(Exception):
|
||||
...
|
||||
|
||||
* **常量(Constants):** 强制使用 SCREAMING\_SNAKE\_CASE(全大写加下划线),定义在模块顶部。
|
||||
* **私有与受保护属性:** \* 单下划线 \_private\_var:表示内部使用(软性约束,仅作提示)。
|
||||
* 双下划线 \_\_strict\_private:触发名称改写(Name Mangling),除非极特殊情况(如防止子类重写),**日常业务开发中不推荐使用**,以免增加调试难度。
|
||||
|
||||
## **现代工程化工具链 (强制执行)**
|
||||
|
||||
**核心理念:能用工具自动修复的风格问题,绝不在 Code Review 中浪费时间口舌。**
|
||||
|
||||
项目中必须配置并使用以下工具链(推荐通过 pre-commit 钩子强制拦截不合规代码):
|
||||
|
||||
1. **项目与依赖管理:uv (核心基石)**
|
||||
* 摒弃传统的 pip、virtualenv 或臃肿的 Poetry,全面拥抱由 Astral 团队用 Rust 编写的 uv。
|
||||
* 它统一了虚拟环境管理、依赖解析和项目运行。使用 uv init 初始化项目,uv add 添加依赖,uv run 执行脚本,极大提升开发构建体验。
|
||||
2. **综合 Linter 与格式化:Ruff**
|
||||
* 同样是 Astral 团队出品的极速工具,完美兼容并替代了 Flake8、isort 和 Black(Ruff 目前已内置极速 formatter)。团队统一在 pyproject.toml 中配置 Ruff 规则。
|
||||
3. **静态类型检查:Mypy**
|
||||
* 开启严格模式。核心业务模块必须通过 Mypy 检查,不允许出现 Any 泛滥的情况。
|
||||
|
||||
## **类型注解 (Type Hinting) 规范**
|
||||
|
||||
**核心理念:动态一时爽,重构火葬场。所有业务接口、函数签名必须带有完整的类型注解。**
|
||||
|
||||
* **基础类型约束:** 充分利用 Python 3.9+ 的内置泛型(如 list, dict,不再需要 from typing import List, Dict)和 Python 3.10+ 的联合类型操作符 |。
|
||||
\# 推荐写法 (Python 3.10+)
|
||||
def process\_user\_data(user\_id: int | str, tags: list\[str\]) \-\> dict\[str, Any\]:
|
||||
pass
|
||||
|
||||
* **可选类型:** 当参数或返回值可能为空时,必须使用 Optional\[T\] 或 T | None。
|
||||
def find\_user(email: str) \-\> User | None:
|
||||
pass
|
||||
|
||||
* **避免 Any 滥用:** 凡是写 Any 的地方,意味着放弃了类型检查。对于复杂的数据结构,应当优先定义 TypedDict 或数据模型类。
|
||||
|
||||
## **核心编码与设计范式**
|
||||
|
||||
### **1\. 数据模型设计 (Pydantic 与 Dataclass 的明确边界)**
|
||||
|
||||
**警惕过度设计:** 绝对不要为了用而用,将整个系统“全盘 Pydantic 化”。Pydantic 实例化时的类型强转和校验是有显著性能开销的,强行铺满内部逻辑会带来极大的工作量和性能负担。
|
||||
|
||||
* **必须使用 Pydantic 的场景(防腐层/系统边界):**
|
||||
* 外部 API 的请求体与响应体验证(如 FastAPI 集成)。
|
||||
* 外部配置文件的解析加载。
|
||||
* 从不可靠来源(如第三方消息队列)消费的复杂 JSON 结构。
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
class UserCreateRequest(BaseModel):
|
||||
name: str
|
||||
email: EmailStr \# 外部输入,必须靠 Pydantic 严防死守
|
||||
age: int | None \= None
|
||||
|
||||
* **必须使用 @dataclass 或 TypedDict 的场景(系统内部):**
|
||||
* 内部 Service 函数之间的参数流转。
|
||||
* 从数据库 ORM 查询出来、组装准备传给下一层的纯内部 DTO。
|
||||
* 这些数据已经是“绝对可信”的,使用标准库的 @dataclass 可以实现近乎 O(1) 的轻量实例化,绝不增加无谓的校验负担。
|
||||
|
||||
### **2\. 函数参数设计 (关键字传参)**
|
||||
|
||||
* 当函数参数超过 3 个,或者包含容易混淆的布尔值时,**强制使用 \* 迫使调用方使用关键字传参**。
|
||||
\# 规范示例:调用此函数时,age 和 is\_active 必须带上参数名
|
||||
def create\_user(name: str, email: str, \*, age: int, is\_active: bool \= True) \-\> User:
|
||||
pass
|
||||
|
||||
\# 调用端:
|
||||
create\_user("John", "john@test.com", age=25, is\_active=False) \# 必须写明 age= 和 is\_active=
|
||||
|
||||
### **3\. 异常处理规约**
|
||||
|
||||
* **禁止吞噬异常:** 绝不允许出现 except Exception: pass 这种掩耳盗铃的代码。
|
||||
* **自定义异常层次:** 模块应当抛出特定业务领域的异常(如继承自 ValueError 的 OrderNotFoundError),而不是直接抛出裸露的 Exception。
|
||||
|
||||
### **4\. 资源释放与安全**
|
||||
|
||||
* **强制使用上下文管理器:** 文件读写、网络会话(如 requests.Session)、数据库连接,必须使用 with 语句包裹,确保资源(哪怕在异常抛出时)能被正确关闭。
|
||||
|
||||
## **性能优化与防坑指南**
|
||||
|
||||
Python 性能上限不高,但不良写法会导致下限极低:
|
||||
|
||||
* **查找操作慎用 List,拥抱 Set/Dict:**
|
||||
* if item in my\_list: 的时间复杂度是 O(n)。对于包含上百个元素的成员判断,**必须**将集合初始化为 Set 或 Dict,以达到 O(1) 的查找性能。
|
||||
* **大数据流拥抱生成器 (Generators):**
|
||||
* 当处理百万级行数的 CSV 或大量数据库记录时,严禁将数据一次性加载到内存的 List 中。**必须使用 yield**。
|
||||
|
||||
def process\_large\_file(filename: str):
|
||||
with open(filename, 'r') as file:
|
||||
for line in file:
|
||||
yield process\_line(line) \# 内存中始终只有一行数据
|
||||
|
||||
* **海量实例的内存优化:**
|
||||
* 当需要实例化上百万个轻量级对象时,必须在类中声明 \_\_slots\_\_ \= \['attr1', 'attr2'\],这能节约约 40% 的内存消耗(阻止 Python 为每个实例创建 \_\_dict\_\_)。
|
||||
|
||||
## **单元测试规范**
|
||||
|
||||
* **测试框架选型:** 统一使用 pytest,废弃 Python 自带的厚重 unittest 类式写法。并通过 uv run pytest 执行。
|
||||
* **测试用例结构:** 遵循 Arrange \- Act \- Assert (准备-执行-断言) 三段式结构。
|
||||
* **Mock 的边界:** 严禁在单元测试中发起真实的 HTTP 网络请求或连接真实的 MySQL 数据库。必须使用 unittest.mock.patch 或 pytest-mock 对外部 IO 依赖进行拦截和模拟。
|
||||
def test\_get\_user\_info(mocker):
|
||||
\# Arrange: 拦截外部数据库调用
|
||||
mocker.patch('myproject.database.fetch', return\_value={"id": 1, "name": "Test"})
|
||||
|
||||
\# Act
|
||||
user \= get\_user\_info(1)
|
||||
|
||||
\# Assert
|
||||
assert user.name \== "Test"
|
||||
@@ -0,0 +1,83 @@
|
||||
# **框架开发实施规范 (Django/DRF)**
|
||||
|
||||
本规范专为基于 Django 与 Django REST Framework (DRF) 的后端项目制定。
|
||||
|
||||
**执行策略**:本规范采用“限制优先”原则。默认不提供多实现方案;未在本文明确允许的绕过做法,一律视为不合规。
|
||||
|
||||
## **工程配置与生态集成 (Settings & Ecosystem)**
|
||||
|
||||
系统底座的配置与外部集成应当保持极度的干净、安全,并充分借力开源社区。
|
||||
|
||||
### **环境解耦与凭证安全**
|
||||
|
||||
* **配置解耦**:严禁将所有配置揉在单个 settings.py 中。必须使用多环境配置拆分(推荐 django-split-settings),严格划分通用配置、组件配置与环境独立配置。
|
||||
* **凭证安全红线**:密钥(如 SECRET\_KEY, DB\_PASSWORD, API Keys)必须从环境变量或配置中心动态读取,**严禁**在代码库中硬编码。
|
||||
|
||||
### **生态复用与外部集成**
|
||||
|
||||
* **严禁重复造轮子**:Django 和 DRF 拥有极其成熟的第三方开源生态。对于标准化的通用需求,**必须**优先集成成熟的第三方库。例如使用 djangorestframework-simplejwt 处理 Token,使用 django-filter 处理复杂查询过滤。
|
||||
* **代理层无状态**:若系统作为中间层代理外部 API(如大模型网关),代理视图禁止落库复杂的业务状态。
|
||||
* **认证逻辑收口**:对接外部系统的身份认证逻辑(如 LDAP、API Key)必须严格收拢在 DRF 的 Authentication 类或 Django 的中间件中,**绝对禁止**在业务 View 中直接读取 Request Headers 做条件分流。
|
||||
|
||||
## **数据层规范 (Models & Serializers)**
|
||||
|
||||
数据层负责实体定义与输入输出的格式化。清晰、防抖的数据层是系统性能的保障。
|
||||
|
||||
### **模型定义与约束**
|
||||
|
||||
* **显式定义主键与审计**:不推荐使用庞大的公共抽象基类隐式继承。业务 Model 应当显式定义主键和必备的审计字段(如 created\_at, updated\_at),避免基类变更带来全局副作用。
|
||||
* **字段防空红线**:字符型字段(CharField, TextField)禁止设置 null=True,必须设为 default=''。
|
||||
* **外键明确声明**:使用 ForeignKey 关联时必须显式指定清晰的 related\_name。
|
||||
* **物理删除优先**:默认优先使用物理删除。仅当业务明确要求审计追溯时引入逻辑删除(is\_deleted)。若启用逻辑删除,必须配合使用带条件的唯一约束以防止重复插入冲突。
|
||||
|
||||
### **序列化层红线 (Serializers)**
|
||||
|
||||
* **禁用全量暴露**:**严禁**在 Serializer 中使用 fields \= '\_\_all\_\_'。必须逐个显式列出对外暴露的字段,防止数据库新增敏感字段后发生意外泄露。
|
||||
* **严防 N+1 查询**:
|
||||
* 列表接口**严禁**使用包含深层嵌套关系的复杂 Serializer,必须为其单独定义轻量级的结构。
|
||||
* 若 Serializer 输出了外键字段,View 层的 QuerySet **必须**配合使用 select\_related 或 prefetch\_related。
|
||||
* **聚合计算隔离**:**严禁**在 SerializerMethodField 中执行 SQL 聚合查询(如 .count(), .sum())。必须在 View 层使用 annotate() 提前计算完毕,Serializer 仅负责读取内存数据。
|
||||
|
||||
## **业务调度层规范 (Views, Services & URLs)**
|
||||
|
||||
**核心原则:Thin View, Fat Service (轻视图,重服务)。**
|
||||
|
||||
View 层仅作为路由调度、参数校验和权限决策的枢纽,绝不可堆砌核心业务逻辑。
|
||||
|
||||
### **视图层职能划分**
|
||||
|
||||
* **基类选型边界**:标准 CRUD 强制使用 ModelViewSet;定制化业务场景强制选用 GenericViewSet 配合 Mixins 按需组合;APIView 仅限非标准资源形态(如透明代理)使用。
|
||||
* **生命周期职责**:
|
||||
* get\_queryset():**必须**在此处完成数据预加载与基于用户身份的数据范围隔离。
|
||||
* get\_serializer\_class():**必须**实现读写分离(如基于 action 返回不同的 Serializer)。
|
||||
* get\_permissions():**必须**基于当前 action 动态分配权限类。
|
||||
|
||||
### **服务层下沉模式 (Service)**
|
||||
|
||||
* **防腐红线**:**严禁**重写 create(), update() 等主调度方法来堆砌业务逻辑(这会破坏 DRF 的标准执行流)。
|
||||
* **标准移交**:复杂的写操作逻辑,应当在 perform\_create() 或 perform\_update() 钩子中,提取并调用独立的 **Service 函数/类** 进行处理。
|
||||
|
||||
### **路由与异常处理**
|
||||
|
||||
* **命名空间绝对隔离**:全局强制采用 NamespaceVersioning 机制。根路由必须携带命名空间,且内部的 urls.py 必须存在 app\_name。反向解析必须带版本号前缀。
|
||||
* **异常抛出代替返回**:遇到业务校验错误,**严禁**在代码中手动 return Response({"error": "xxx"})。**必须**直接抛出异常(如 raise ValidationError),交由全局的 exception\_handler 统一格式化。
|
||||
* **统一响应壳**:严禁在 View 中手动构建类似 {"code": 0, "data": ...} 的字典,必须交由自定义的全局 Renderer 统一包装。
|
||||
|
||||
## **权限管控与数据隔离 (Permissions)**
|
||||
|
||||
系统中的权限管控是防范越权访问、越权篡改的核心防线。必须绝对交由框架层(鉴权基类、过滤器)统一拦截。
|
||||
|
||||
### **功能权限 (操作级拦截)**
|
||||
|
||||
* **禁用硬编码判断**:**绝对禁止**在业务 Service 或 View 方法内部使用硬编码的 if 语句拦截权限(例如:if request.user.role \!= 'admin': raise PermissionDenied)。
|
||||
* **规范抽象**:功能权限必须抽象并继承 DRF 的 BasePermission,统一在 View 的 permission\_classes 属性中进行声明与挂载。
|
||||
|
||||
### **对象级权限 (防越权篡改)**
|
||||
|
||||
* **必须重写对象判定**:对于针对单一资源的操作(如修改、删除),如果仅允许资源的拥有者或管理员操作,**必须**在权限类中实现 has\_object\_permission。
|
||||
* **防跳过红线**:DRF 仅在调用 self.get\_object() 时才会触发对象级鉴权。在自定义 Action 中操作单个资源时,**必须**首先显式调用该方法获取对象,严禁直接使用 Model.objects.get(pk=pk) 从而绕过权限检查!
|
||||
|
||||
### **数据范围隔离 (防越权查看)**
|
||||
|
||||
* **后端绝对阻断**:绝对禁止依靠前端“不显示该列表”或“隐藏入口”来做数据隔离防护。
|
||||
* **规范落实**:不同租户(组织、用户)的数据隔离,必须通过重写 View 的 get\_queryset() 进行彻底的 QuerySet 过滤来实现。
|
||||
Reference in New Issue
Block a user