1. orm删除数据为什么通常都是先查询后删除?

  • 先查询,针对查询结果做检查,可以避免删除不存在的数据,或者删除了不该删除的数据,结果更可预期。
  • 如果要针对对象级权限检查,通常都是需要先查询,再做检查,再删除。
  • 执行对象级删除,orm可以执行级联删除动作,以及before_delete和after_delete等钩子操作。但是直接绕过对象查询,直接进行sql级别删除,没有这些钩子操作。

2 对象的局部更新 vs 整体更新

  • 整体更新(PUT)
    定义:客户端提交整个资源对象,后端以新对象替换旧对象。
    特点:
    • 必须包含完整对象的所有字段。
    • 缺失字段可能被视为“置空”或“删除”。
    • 适合更新“全部信息”的场景。
      优点:
    • 实现简单,对象状态明确。
      缺点:
    • 数据传输冗余,不适合字段较多的对象或频繁变更的场景。
    • 误操作风险较高(漏字段即为置空)。不过可以通过前端校验或后端逻辑来避免。
  • 局部更新(PATCH)
    定义:客户端只提交需要修改的字段,后端仅更新这些字段。
    特点:仅包含变化字段。
    优点:请求体小,网络效率高。风险低,不易误改未变化字段。
    缺点:实现稍复杂,要前端或后端跟踪变更字段。
  • 前端处理策略
    可通过 UI 框架的字段监听(如 React 的 onChange,AntD 的 onValuesChange)收集变化字段。
    提交前记录变更字段,只上传需要更新的键值对。
  • 后端处理策略
    整体更新:直接替换数据库中整行数据。
    局部更新:提取提交字段,动态构造更新语句。
    后端通常返回最新完整对象,用于前端状态同步和 UI 更新。
    fastapi中,对于 PATCH,一般使用对象的 exclude_unset=True 过滤未提交字段。

3. python中的mapping类型

  • 下面代码是httpx中AsyncClient().request()方法中的params参数的类型定义,可见当中用链Mapping类型
    1
    2
    3
    4
    5
    6
    7
    8
    QueryParamTypes = Union[
    "QueryParams",
    Mapping[str, Union[PrimitiveData, Sequence[PrimitiveData]]],
    List[Tuple[str, PrimitiveData]],
    Tuple[Tuple[str, PrimitiveData], ...],
    str,
    bytes,
    ]
  • Mapping类型是dict的父类,定义了一种不可变的字典,所以可以用dict作为Mapping类型参数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from collections.abc import Mapping

    # 验证 dict 是否为 Mapping 的子类
    print(issubclass(dict, Mapping)) # 输出: True

    # 创建一个 dict 对象
    my_dict = {"apple": 1, "banana": 2}

    # 验证 dict 对象是否为 Mapping 类型的实例
    print(isinstance(my_dict, Mapping)) # 输出: True