签入版本
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# 分页规范
|
||||
|
||||
## 概述
|
||||
|
||||
统一使用 `pageNo`/`pageSize` 作为分页参数,Django `Paginator` 封装分页逻辑,返回标准分页结构。
|
||||
|
||||
:::tip 分页约定
|
||||
- 前端传递 `pageNo`(页码,从 1 开始)和 `pageSize`(每页条数)
|
||||
- 后端返回 `{records, total, size, current, pages}` 结构
|
||||
- 默认每页 10 条(`PAGE_SIZE = 10`)
|
||||
:::
|
||||
|
||||
## 请求参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| `pageNo` | int | 否 | 1 | 页码,从 1 开始 |
|
||||
| `pageSize` | int | 否 | 10 | 每页条数 |
|
||||
|
||||
### 请求示例
|
||||
|
||||
```bash
|
||||
# GET 请求
|
||||
GET /example/page?pageNo=1&pageSize=10
|
||||
|
||||
# 带筛选条件
|
||||
GET /example/page?pageNo=1&pageSize=10&name=案例&type=1&status=1
|
||||
```
|
||||
|
||||
## 响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "案例名称",
|
||||
"type": 1,
|
||||
"status": 1,
|
||||
"sort": 1,
|
||||
"createUser": "admin",
|
||||
"createTime": "2026-01-01 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 50,
|
||||
"size": 10,
|
||||
"current": 1,
|
||||
"pages": 5
|
||||
},
|
||||
"msg": "操作成功",
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `records` | array | 当前页数据列表 |
|
||||
| `total` | int | 总记录数 |
|
||||
| `size` | int | 每页条数 |
|
||||
| `current` | int | 当前页码 |
|
||||
| `pages` | int | 总页数 |
|
||||
|
||||
## Service 实现
|
||||
|
||||
### 分页查询方法
|
||||
|
||||
```python
|
||||
from django.core.paginator import Paginator, PageNotAnInteger, InvalidPage, EmptyPage
|
||||
from constant.constants import PAGE_SIZE
|
||||
from utils import R
|
||||
|
||||
def get_example_page(request):
|
||||
"""查询案例分页数据"""
|
||||
try:
|
||||
# 获取分页参数
|
||||
page_no = int(request.GET.get('pageNo', 1))
|
||||
page_size = int(request.GET.get('pageSize', PAGE_SIZE))
|
||||
|
||||
# 构建基础查询(只查询未删除的记录)
|
||||
query = Example.objects.filter(is_delete=False)
|
||||
|
||||
# 应用筛选条件
|
||||
query = _apply_filters(query, request)
|
||||
|
||||
# 按排序字段升序排列
|
||||
query = query.order_by("sort")
|
||||
|
||||
# 执行分页查询
|
||||
paginator = Paginator(query, page_size)
|
||||
try:
|
||||
page_list = paginator.page(page_no)
|
||||
except (PageNotAnInteger, InvalidPage, EmptyPage):
|
||||
# 页码无效时默认返回第一页
|
||||
page_list = paginator.page(1)
|
||||
page_no = 1
|
||||
|
||||
# 构建并返回分页数据
|
||||
page_data = _build_page_data(page_list, paginator, page_no, page_size)
|
||||
return R.ok(data=page_data)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"查询案例分页数据异常: {str(e)}")
|
||||
return R.failed(msg="查询失败,请稍后重试")
|
||||
```
|
||||
|
||||
### 分页数据构建
|
||||
|
||||
```python
|
||||
def _build_page_data(page_list, paginator, page_no, page_size):
|
||||
"""构建分页返回数据"""
|
||||
records = []
|
||||
for item in page_list:
|
||||
record = {
|
||||
'id': item.id,
|
||||
'name': item.name,
|
||||
'type': item.type,
|
||||
'status': item.status,
|
||||
'sort': item.sort,
|
||||
'createUser': item.create_user,
|
||||
'createTime': format_datetime(item.create_time),
|
||||
'updateUser': item.update_user,
|
||||
'updateTime': format_datetime(item.update_time),
|
||||
}
|
||||
records.append(record)
|
||||
|
||||
return {
|
||||
'records': records,
|
||||
'total': paginator.count, # 总记录数
|
||||
'size': page_size, # 每页大小
|
||||
'current': page_no, # 当前页码
|
||||
'pages': paginator.num_pages # 总页数
|
||||
}
|
||||
```
|
||||
|
||||
### 筛选条件应用
|
||||
|
||||
```python
|
||||
def _apply_filters(queryset, request):
|
||||
"""应用查询筛选条件"""
|
||||
# 名称模糊筛选
|
||||
name = request.GET.get('name')
|
||||
if name:
|
||||
queryset = queryset.filter(name__contains=name)
|
||||
|
||||
# 类型精确筛选
|
||||
type = request.GET.get('type')
|
||||
if type:
|
||||
queryset = queryset.filter(type=type)
|
||||
|
||||
# 状态精确筛选
|
||||
status = request.GET.get('status')
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
return queryset
|
||||
```
|
||||
|
||||
:::tip 筛选字段说明
|
||||
- 字符串字段使用 `__contains` 实现模糊查询(LIKE)
|
||||
- 整数字段直接使用 `=` 实现精确匹配
|
||||
- 空值自动跳过,无需手动判断
|
||||
:::
|
||||
|
||||
## View 示例
|
||||
|
||||
```python
|
||||
@method_decorator(check_login, name="get")
|
||||
class ExamplePageView(PermissionRequired, View):
|
||||
"""案例分页数据查询视图"""
|
||||
permission_required = ("sys:example:page",)
|
||||
|
||||
@operation_log(title="案例管理-查询分页列表", log_type=LogType.QUERY)
|
||||
def get(self, request):
|
||||
result = services.get_example_page(request)
|
||||
return result
|
||||
```
|
||||
|
||||
:::tip 权限标识
|
||||
分页接口权限标识格式:`sys:{模块名}:page`
|
||||
:::
|
||||
|
||||
## 总结
|
||||
|
||||
分页规范统一使用 `pageNo`/`pageSize` 参数,通过 Django `Paginator` 处理分页逻辑。Service 层构建查询、应用筛选、执行分页、构建返回数据。响应使用 `R.ok(data=page_data)` 封装标准分页结构,前端可直接使用 `records`/`total`/`pages` 渲染列表和分页组件。
|
||||
Reference in New Issue
Block a user