ITM-0011 draft
This commit is contained in:
@@ -0,0 +1,173 @@
|
|||||||
|
ITM: 11
|
||||||
|
Title: 爱特工作室程序部后端开发规范
|
||||||
|
Author: Yuixiang Cai <caiyuxiang@itstudio.club>, Liu Yang <liuyang@itstudio.club>
|
||||||
|
Created: 2021-12-17
|
||||||
|
Status: draft
|
||||||
|
|
||||||
|
|
||||||
|
简介
|
||||||
|
====================
|
||||||
|
|
||||||
|
爱特程序部主要工作是后端开发,基于 `Django` 框架: https://www.djangoproject.com/
|
||||||
|
多数情况下和前端部门合作进行前后端分离的开发。
|
||||||
|
|
||||||
|
目录
|
||||||
|
====================
|
||||||
|
|
||||||
|
0. 项目组织
|
||||||
|
1. settings.py
|
||||||
|
2. models.py
|
||||||
|
3. serializers.py
|
||||||
|
4. views.py
|
||||||
|
5. urlpatterns && Router
|
||||||
|
|
||||||
|
正文
|
||||||
|
====================
|
||||||
|
|
||||||
|
0. 项目组织
|
||||||
|
|
||||||
|
在大多数时候,项目可能包括不止一个 APP,将这些 APP 全部收录到一个 `apps` 文件夹中,并将该文件夹设置为 Python 的包。
|
||||||
|
|
||||||
|
一个项目的目录树大体如下:
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── apps
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ └── <app_name>
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── admin.py
|
||||||
|
│ ├── apps.py
|
||||||
|
│ ├── migrations
|
||||||
|
│ │ └── __init__.py
|
||||||
|
│ ├── models.py
|
||||||
|
│ ├── serializers.py
|
||||||
|
│ ├── tests.py
|
||||||
|
│ └── views.py
|
||||||
|
├── <project_name>
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── asgi.py
|
||||||
|
│ ├── settings.py
|
||||||
|
│ ├── urls.py
|
||||||
|
│ └── wsgi.py
|
||||||
|
├── .gitignore
|
||||||
|
├── manage.py
|
||||||
|
└── config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 便于统一化管理,减少根目录下的文件数。
|
||||||
|
|
||||||
|
1. settings.py
|
||||||
|
|
||||||
|
`settings.py` 里的敏感配置信息如: `SECRET_KEY`,数据库的账号密码,STMP 等服务的账号密码,禁止明文写在文件中,请使用配置文件的方式读入并在 `.gitignore` 文件中忽略配置文件。
|
||||||
|
|
||||||
|
示例代码:
|
||||||
|
|
||||||
|
```
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Configuration File
|
||||||
|
with open('./conf.json', 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
SECRET_KEY = config.get('SECRET_KEY')
|
||||||
|
|
||||||
|
MYSQL_DATABASE_NAME = config.get('MYSQL_DATABASE_NAME')
|
||||||
|
MYSQL_DATABASE_USER = config.get('MYSQL_DATABASE_USER')
|
||||||
|
MYSQL_DATABASE_PASSWORD = config.get('MYSQL_DATABASE_PASSWORD')
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 避免上传到 GitHub 等平台时密码泄露。
|
||||||
|
|
||||||
|
2. Model 层规范
|
||||||
|
|
||||||
|
Model 类应该写在每个 app 下的 `models.py` 文件中,同时每个 Model 的每个字段应添加文字描述,例如:
|
||||||
|
|
||||||
|
`content = models.TextField('内容')`
|
||||||
|
|
||||||
|
对于常量使用 `ChoiceField` 类型,例如:
|
||||||
|
|
||||||
|
```
|
||||||
|
GENDER_CHOICES = (
|
||||||
|
(0, '女'),
|
||||||
|
(1, '男'),
|
||||||
|
(2, '隐藏')
|
||||||
|
)
|
||||||
|
class Person(models.Model):
|
||||||
|
gender = models.IntegerField('性别', choices=GENDER_CHOICES, default=2)
|
||||||
|
```
|
||||||
|
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 直观,只需要看 Model 类就可以理解数据库内的表。
|
||||||
|
- 集中管理映射关系,外部显示的改变不会影响数据库内的字段。
|
||||||
|
|
||||||
|
3. serializers.py
|
||||||
|
|
||||||
|
Django RestFrameWork(drf) 中增加了序列化器,它可以代替表单快捷的完成校验和对数据库的操作。
|
||||||
|
|
||||||
|
在校验中如果出现字段错误,抛出异常而不是返回 False。异常对应的状态信息参考 View 层对返回值设置的规范。
|
||||||
|
|
||||||
|
4. views.py
|
||||||
|
|
||||||
|
使用基于类的视图 `ViewSet` 或者 `APIView` 而不是函数。并在每个类中增加对整体模块逻辑的描述注释,在函数上增加函数功能的描述注释。
|
||||||
|
|
||||||
|
注释参考示例:
|
||||||
|
|
||||||
|
```
|
||||||
|
class <ClassName>(APIView):
|
||||||
|
"""
|
||||||
|
用户博客模块的逻辑
|
||||||
|
"""
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
:description: 对当前用户新增一篇博客
|
||||||
|
:author: ctwo
|
||||||
|
:date: 2021/12/17
|
||||||
|
:param request: 请求
|
||||||
|
:return: Response
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 基于类的视图更符合面向对象和 Restful 规范,能更好的将接口归档。
|
||||||
|
|
||||||
|
在和前端交互的过程中,以 Json 数据格式为主,后端的返回格式应该如下:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200, // 状态码
|
||||||
|
"msg": "OK", // 必要的返回描述信息
|
||||||
|
"data": {} // 数据
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同时,使用枚举类型绑定状态码和返回描述信息,如:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ResponseStatus(Enum):
|
||||||
|
OK = (20000, '成功')
|
||||||
|
UNEXPECTED_ERROR = (50000, '意外错误')
|
||||||
|
METHOD_NOT_ALLOWED_ERROR = (40000, '请求方法错误')
|
||||||
|
```
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 避免了重复的在视图函数中写返回信息的字符串,也便于规范接口文档
|
||||||
|
|
||||||
|
4. urlpatterns 和 Router 规范
|
||||||
|
|
||||||
|
使用 POST 方法或者带有参数的 GET 方法而不是将要查询的字段如 id 拼在 URL 中。
|
||||||
|
|
||||||
|
不推荐的写法:`path("^blog/(?P<user_id>.*)$", <view_get_func>, name=<url_name>)`
|
||||||
|
|
||||||
|
而采用 `path("blog/", <view_post_func>, name=<url_name>)`
|
||||||
|
|
||||||
|
这样的好处在于:
|
||||||
|
|
||||||
|
- 降低路由复杂性,少写复杂正则表达式,增强可读性
|
||||||
Reference in New Issue
Block a user