batch_lookup.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """批量预取商品/分类/单位,消除明细循环内 N+1。"""
  2. from typing import List, Optional, Tuple
  3. from sqlalchemy.orm import Session
  4. from sqlalchemy import and_
  5. from app.models.models import BasProduct, BasProductCategory, BasProductUnit
  6. def prefetch_products_categories_units(
  7. db: Session,
  8. product_ids: List[str],
  9. extra_unit_ids: Optional[List[str]] = None,
  10. ) -> Tuple[dict, dict, dict]:
  11. """返回 (product_map, category_name_map, unit_name_map),key 均为 str(id)。"""
  12. clean_pids = [str(x) for x in (product_ids or []) if x]
  13. products = []
  14. if clean_pids:
  15. products = db.query(BasProduct).filter(
  16. and_(BasProduct.id.in_(clean_pids), BasProduct.is_del == 0)
  17. ).all()
  18. product_map = {str(p.id): p for p in products}
  19. category_ids = list({str(p.category_id) for p in products if getattr(p, "category_id", None)})
  20. category_map: dict = {}
  21. if category_ids:
  22. categories = db.query(BasProductCategory).filter(
  23. and_(BasProductCategory.id.in_(category_ids), BasProductCategory.is_del == 0)
  24. ).all()
  25. category_map = {str(c.id): str(c.name or "") for c in categories}
  26. unit_ids = {str(p.unit_id) for p in products if getattr(p, "unit_id", None)}
  27. if extra_unit_ids:
  28. unit_ids.update(str(x) for x in extra_unit_ids if x)
  29. unit_map: dict = {}
  30. clean_uids = [x for x in unit_ids if x]
  31. if clean_uids:
  32. units = db.query(BasProductUnit).filter(
  33. and_(BasProductUnit.id.in_(clean_uids), BasProductUnit.is_del == 0)
  34. ).all()
  35. unit_map = {str(u.id): str(u.name or "") for u in units}
  36. return product_map, category_map, unit_map
  37. def build_category_path_map(db: Session, category_ids: List[str]) -> dict:
  38. """批量构建分类路径(一级/二级用 / 连接)。"""
  39. clean_ids = [str(x).strip() for x in (category_ids or []) if x]
  40. if not clean_ids:
  41. return {}
  42. categories = db.query(BasProductCategory).filter(BasProductCategory.is_del == 0).all()
  43. by_id = {str(c.id): c for c in categories}
  44. result: dict = {}
  45. for cid in clean_ids:
  46. names: List[str] = []
  47. cur = cid
  48. seen = set()
  49. depth = 0
  50. while cur and depth < 24 and cur not in seen:
  51. seen.add(cur)
  52. cat = by_id.get(cur)
  53. if not cat:
  54. break
  55. names.insert(0, (getattr(cat, "name", None) or "").strip())
  56. pid = getattr(cat, "parent_id", None)
  57. cur = str(pid).strip() if pid else ""
  58. depth += 1
  59. result[cid] = "/".join(n for n in names if n)
  60. return result