Flask-MySQL列表视图分页API实现问题求助 附PropertyView代码
Flask MySQL 列表分页接口实现方案
原代码待修正的基础问题
- 原查询逻辑通过
.all()全量加载Property表的所有数据,数据量上升后会出现内存占用过高、接口响应超时的问题 - 用户存在性判断逻辑错误:SQLAlchemy的
first()方法查询无结果时返回None,和字符串"null"的恒等判断永远不成立,会跳过用户校验逻辑 - 存在重复读取
request.json的冗余代码,无实际业务作用 - JWT解析未做前置校验,缺失请求头、token格式错误时会直接抛出未捕获异常
- 查询类接口返回201状态码不符合规范,201是资源创建类操作的返回码
标准分页实现逻辑
借助SQLAlchemy内置的分页能力完成查询截断,无需手写原生SQL的limit/offset逻辑:
- 从URL查询参数读取页码、单页容量参数,设置默认值与边界限制,防止前端传入非法值
- 替换全量查询为分页查询,仅加载当前页需要的数据
- 返回结构中附带分页元数据,方便前端渲染分页控件
修改后的完整可运行代码如下:
class PropertyView(Resource): def get(self): try: # JWT 解析逻辑 auth_header = request.headers.get('Authorization') if not auth_header: return ResponseGenerator( message='未携带身份认证信息', status=status.HTTP_401_UNAUTHORIZED ).make_error_response() token = jwt.decode(auth_header, "secret", algorithm="HS256") current_email = token.get('email') # 校验当前用户是否存在 current_user = User.query.filter_by(email=current_email).first() if not current_user: return ResponseGenerator( message='当前登录用户不存在', status=status.HTTP_403_FORBIDDEN ).make_error_response() # 分页参数校验与读取 page = request.args.get('page', 1, type=int) per_page = request.args.get('per_page', 10, type=int) # 边界限制:单页最多返回100条,避免一次拉取过多数据 per_page = min(per_page, 100) # 分页查询,按id倒序 paginate_result = Property.query.order_by(Property.id.desc()).paginate( page=page, per_page=per_page, error_out=False ) # 序列化当前页的Property数据 property_list = [] for property_obj in paginate_result.items: property_list.append({ 'id': property_obj.id, 'address': property_obj.address, "latitude": property_obj.latitude, "longitude": property_obj.longitude, "cdr_date": property_obj.cdr_date, "building_grossfloor_area": property_obj.building_grossfloor_area, "multi_family": property_obj.multi_family, "artist_studios": property_obj.artist_studios, "max_building_height": property_obj.max_building_height, "stories": property_obj.stories, "retail_commercial_sf": property_obj.retail_commercial_sf, "parking_spaces": property_obj.parking_spaces, "bike_spaces": property_obj.bike_spaces, "architect": property_obj.architect, "developer": property_obj.developer, "site_area": property_obj.site_area, "picture_1": property_obj.picture_1, "picture_2": property_obj.picture_2, "original_name": property_obj.original_name }) # 组装包含分页元信息的返回结构 response_data = { "list": property_list, "pagination": { "total": paginate_result.total, "pages": paginate_result.pages, "current_page": page, "per_page": per_page, "has_next": paginate_result.has_next, "has_prev": paginate_result.has_prev } } return ResponseGenerator( data=response_data, status=status.HTTP_200_OK ).make_success_response() except Exception as e: logger.exception(e) return ResponseGenerator( message=f'Exception: {str(e)}', status=status.HTTP_400_BAD_REQUEST ).make_error_response()
实现注意事项
paginate()方法配置error_out=False时,页码超出总页数范围会返回空列表,不会自动触发404错误,兼容前端异常场景- 分页参数通过
request.args从URL查询参数获取,不要从请求体JSON中读取查询类参数,符合接口设计通用规范 - 对单页返回数据量做硬上限限制(比如最多100条),避免大请求造成服务端压力
内容的提问来源于stack exchange,提问作者Tushar Baradia
相关产品推荐
相关产品推荐

