40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""ORM 通用辅助"""
|
|
from django.db.models import Subquery, OuterRef, Sum, Value, DecimalField
|
|
from django.db.models.functions import Coalesce
|
|
|
|
|
|
def inflight_sum(model, fk, submit_isnull_path, amount, *, max_digits=12, decimal_places=1):
|
|
"""未提交单据的"在途"聚合量(存量之外正在出入库/在制/在途交接的数量)。
|
|
|
|
用关联标量子查询实现, 不与主表 JOIN, 因此可在同一个 queryset 上安全叠加
|
|
多个不同多值关系的聚合而不会因笛卡尔积翻倍(Django 多聚合经典陷阱)。
|
|
|
|
:param model: 明细模型, 如 MIOItem / Mlogb / Handoverb
|
|
:param fk: 明细指向主表的外键名, 如 'mb' / 'wm_in' / 'wm'
|
|
:param submit_isnull_path: 判定"未提交"的查询路径, 如 'mio__submit_time__isnull'
|
|
:param amount: 参与求和的数量字段, 如 'count' / 'count_use'
|
|
"""
|
|
return Coalesce(
|
|
Subquery(
|
|
model.objects
|
|
.filter(**{fk: OuterRef('pk'), submit_isnull_path: True})
|
|
.order_by() # 清掉默认排序, 否则污染 GROUP BY
|
|
.values(fk) # 按外键分组 -> 每个主键一行
|
|
.annotate(_s=Sum(amount))
|
|
.values('_s') # 取出标量
|
|
),
|
|
Value(0, output_field=DecimalField(max_digits=max_digits, decimal_places=decimal_places)),
|
|
)
|
|
|
|
|
|
def restql_wants(request, field_names):
|
|
"""django-restql 稀疏字段判断: 用于"不需要的字段就不做昂贵注解"。
|
|
|
|
未带 query 参数 -> 视为需要全部字段(保持默认行为);
|
|
带了 query -> 仅当其中点名了任一 field_names 时才认为需要。
|
|
"""
|
|
query = request.query_params.get('query') if request else None
|
|
if not query:
|
|
return True
|
|
return any(name in query for name in field_names)
|