Become a sponsor

统一使用 pageNo/pageSize 作为分页参数,BaseService.get_page() 封装分页逻辑,返回标准分页结构。
分页约定
pageNo(页码,从 1 开始)和 pageSize(每页条数){records, total, size, current, pages} 结构PAGE_SIZE = 10)| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
pageNo | int | 否 | 1 | 页码,从 1 开始 |
pageSize | int | 否 | 10 | 每页条数 |
# GET 请求
GET /api/v1/position/page?pageNo=1&pageSize=10
# 带筛选条件
GET /api/v1/position/page?pageNo=1&pageSize=10&name=开发&status=1{
"code": 0,
"data": {
"records": [
{
"id": 1,
"name": "开发工程师",
"status": 1,
"statusText": "在用",
"sort": 1,
"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 | 总页数 |
def get_page(self, request) -> R:
"""分页查询"""
page, limit = parse_pagination(request)
query = self._build_page_query(request)
items, total = self.repo.paginate(page, limit, query)
# 超页自动回退第 1 页
if page > 1 and not items:
page = 1
items, total = self.repo.paginate(page, limit, query)
result = [self._serialize(item) for item in items]
return R.page(result, total, page, limit)超页回退
当请求的页码超过总页数时(如删除数据后前端未刷新),自动回退到第 1 页,避免返回空数据。
def _build_page_query(self, request):
"""组装分页查询:声明字段过滤 + 排序"""
query = self.repo.filter()
query = self._apply_page_filters(query, request)
for field_name, direction in self.page_order_by:
column = getattr(self.model, field_name)
query = query.order_by(column.asc() if direction == 'asc' else column.desc())
return queryclass PositionService(BaseService[Position]):
# 模糊查询字段:name LIKE %值%
page_like_fields = ('name',)
# 等值查询字段:status = 值
page_eq_fields = ('status',)
# 排序规则
page_order_by = (('sort', 'asc'),)
:::tip 过滤字段说明
- `page_like_fields`:从 query_params 取同名参数,自动应用 `LIKE %值%`,空值跳过
- `page_eq_fields`:从 query_params 取同名参数,自动应用 `=值`,空值跳过
- 两种字段均自动跳过 None/空字符串,无需手动判断
:::
## Repository 分页实现
```python
def paginate(self, page_no: int = 1, page_size: int = PAGE_SIZE, query=None):
"""分页查询,返回 (items, total)"""
q = query if query is not None else self.db.query(self.model)
q = q.filter(self._soft_col() == 0) # 自动软删过滤
total = q.count()
items = q.limit(page_size).offset((page_no - 1) * page_size).all()
return items, total@router.get('/page', summary='查询分页数据')
@permission_required("sys:position:page")
def page(request: Request):
"""获取岗位分页列表"""
return position_service.get_page(request)权限标识
分页接口权限标识格式:sys:{模块名}:page
子类可覆盖 _apply_page_filters 添加固定过滤条件:
def _apply_page_filters(self, query, request):
"""添加固定过滤:只显示启用状态的数据"""
query = super()._apply_page_filters(query, request)
query = query.filter(self.model.status == 1)
return query分页规范统一使用 pageNo/pageSize 参数,通过 BaseService.get_page() 自动处理分页逻辑。子类只需声明 page_like_fields/page_eq_fields/page_order_by 即可获得完整的分页能力。响应使用 R.page() 封装标准分页结构,前端可直接使用 records/total/pages 渲染列表和分页组件。