schoolclass.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import copy
  4. from typing import Optional, Union
  5. from fastapi import APIRouter, Depends, Query, Path
  6. from sqlalchemy import text, desc
  7. from sqlalchemy.ext.asyncio import AsyncSession
  8. from starlette.background import BackgroundTasks
  9. from bgtask.tasks import bgtask_delete_related_object
  10. from crud.school import crud_class, crud_school, crud_grade
  11. from models.school import SchoolClass
  12. from models.user import Admin
  13. from schemas.school.school import (SchoolClassList, NewClassInfo, SchoolClassDetail, ClassInDB,
  14. UpdateClass)
  15. from utils.depends import get_async_db, get_current_user
  16. router = APIRouter()
  17. # 班级列表
  18. @router.get("/classes",
  19. response_model=SchoolClassList,
  20. response_model_exclude_none=True,
  21. summary="班级列表")
  22. async def get_classes(page: Optional[int] = None,
  23. size: Optional[int] = None,
  24. sid: int = Query(None, description="学校ID"),
  25. gid: int = Query(None, description="年级ID"),
  26. db: AsyncSession = Depends(get_async_db),
  27. current_user: Admin = Depends(get_current_user)):
  28. _q = {}
  29. if sid is not None:
  30. _q["school_id"] = sid
  31. if gid is not None:
  32. _q["grade_id"] = gid
  33. if ((page is not None) and page >= 1) and ((size is not None) and size >= 1):
  34. offset = (page - 1) * size
  35. else:
  36. offset = size = None
  37. total, items = await crud_class.find_all(db, filters=_q, offset=offset, limit=size)
  38. return {"total": total, "data": items}
  39. @router.post("/classes",
  40. response_model=SchoolClassDetail,
  41. response_model_exclude_none=True,
  42. summary="新建班级")
  43. async def create_class(info: NewClassInfo,
  44. db: AsyncSession = Depends(get_async_db),
  45. current_user: Admin = Depends(get_current_user)):
  46. info_dict = info.dict(exclude_none=True)
  47. if not info_dict:
  48. return {"errcode": 400, "mess": "提交参数为空!"}
  49. if not (("name" not in info_dict) or ("amount" not in info_dict)): # 单个建班或快速建班
  50. return {"errcode": 400, "mess": "缺少班级名称或数量"}
  51. # 判断学校是否存在
  52. db_school = await crud_school.find_one(db,
  53. filters={"id": info_dict["school_id"]},
  54. return_fields=["name"])
  55. if not db_school:
  56. return {"errcode": 404, "mess": "学校不存在!"}
  57. else:
  58. info_dict["school_name"] = db_school.name
  59. # 判断年级是否存在
  60. db_grade = await crud_grade.find_one(db,
  61. filters={
  62. "school_id": info.school_id,
  63. "id": info.grade_id
  64. },
  65. return_fields=["name"])
  66. if not db_grade:
  67. return {"errcode": 404, "mess": "年级不存在!"}
  68. else:
  69. info_dict["grade_name"] = db_grade.name
  70. # 新建班级,如果存在amount,表示为快速建班,否则为普通建班
  71. new_classes = []
  72. info_dict["creator_id"] = info_dict["editor_id"] = current_user.id
  73. info_dict["creator_name"] = info_dict["editor_name"] = current_user.username
  74. if info_dict.get("amount", 0):
  75. # 查询当前学校+当前年级下是否存在班级
  76. _, db_class = await crud_class.find_all(db,
  77. filters={
  78. "school_id": info.school_id,
  79. "grade_id": info.grade_id
  80. },
  81. return_fields=["name"])
  82. db_class_names = [x.name for x in db_class]
  83. for i in range(1, info_dict.pop("amount") + 1):
  84. name = f"{info_dict['grade_name']}{str(i)}班"
  85. if name not in db_class_names:
  86. temp = copy.deepcopy(info_dict)
  87. temp["name"] = name
  88. new_classes.append(temp)
  89. else:
  90. info_dict["name"] = info_dict["grade_name"] + info_dict["name"]
  91. new_classes.append(ClassInDB(**info_dict))
  92. item = await crud_class.insert_many(db, new_classes)
  93. if item is None:
  94. return {"errcode": 400, "mess": "存在同名班级"}
  95. else:
  96. return {"data": item}
  97. @router.get("/classes/{cid}",
  98. response_model=SchoolClassDetail,
  99. response_model_exclude_none=True,
  100. summary="班级详情")
  101. async def get_class(cid: str = Path(..., description="班级ID"),
  102. db: AsyncSession = Depends(get_async_db),
  103. current_user: Admin = Depends(get_current_user)):
  104. db_obj = await crud_class.find_one(db, filters={"id": cid})
  105. return {"data": db_obj} if db_obj else {"errcode": 404, "mess": "班级不存在!"}
  106. # 更新班级
  107. @router.put("/classes/{cid}",
  108. response_model=SchoolClassDetail,
  109. response_model_exclude_none=True,
  110. summary="更新班级")
  111. async def update_class(info: UpdateClass,
  112. cid: int = Path(..., description="班级ID"),
  113. db: AsyncSession = Depends(get_async_db),
  114. current_user: Admin = Depends(get_current_user)):
  115. # 判断提交参数
  116. info_dict = info.dict(exclude_none=True)
  117. if not info_dict:
  118. return {"errcode": 400, "mess": "提交参数为空!"}
  119. # 判断班级是否存在
  120. db_obj = await crud_class.find_one(db, filters={"id": cid})
  121. if not db_obj:
  122. return {"errcode": 404, "mess": "班级不存在!"}
  123. # 如果学校ID不等于班级的school_id, 则更新
  124. if ("school_id" in info_dict) and (db_obj.school_id != info_dict["school_id"]):
  125. db_school = await crud_school.count(db,
  126. filters={"id": info.school_id},
  127. return_fields=["name"])
  128. if not db_school:
  129. return {"errcode": 404, "mess": "学校不存在!"}
  130. else:
  131. info.school_name = db_school.name
  132. # 判断年级是否存在
  133. if ("grade_id" in info_dict) and (db_obj.grade_id != info_dict["grade_id"]):
  134. db_grade = await crud_grade.count(db,
  135. filters={
  136. "school_id": info.school_id,
  137. "id": info.grade_id
  138. },
  139. return_fields=["name"])
  140. if not db_grade:
  141. return {"errcode": 404, "mess": "年级不存在!"}
  142. else:
  143. info.grade_name = db_grade.name
  144. # 更新班级
  145. info.editor_id = current_user.id
  146. info.editor_name = current_user.username
  147. db_obj = await crud_class.update(db, db_obj, info)
  148. return {"data": db_obj}
  149. # 删除班级
  150. @router.delete("/classes/{cid}",
  151. response_model=SchoolClassDetail,
  152. response_model_exclude_none=True,
  153. summary="删除班级")
  154. async def delete_class(bgtask: BackgroundTasks,
  155. cid: Union[int,
  156. str] = Path(...,
  157. description="学生ID,批量删除传用逗号分隔ID(str),单个删除传ID(int)"),
  158. db: AsyncSession = Depends(get_async_db),
  159. current_user: Admin = Depends(get_current_user)):
  160. # 查询所有班级
  161. if isinstance(cid, int):
  162. deleted_count = 1
  163. _q = [SchoolClass.id == cid]
  164. else:
  165. cids = [int(x.strip()) for x in cid.split(',') if x.strip()]
  166. deleted_count = len(cids)
  167. _q = [SchoolClass.id.in_(cids)]
  168. total, db_objs = await crud_class.find_all(db, filters=_q)
  169. # 删除
  170. for item in db_objs:
  171. await crud_class.delete(db, obj_id=item.id)
  172. bgtask.add_task(bgtask_delete_related_object, cid=item.id)
  173. return {
  174. "data": total,
  175. "mess": "success" if total == deleted_count else f"成功:{total},失败: {deleted_count - total}"
  176. }