From e1491ead63764aa650c3f54eeb039203ebd5d9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=80=BE=E9=9F=B3=E8=8A=82?= <17608307+sansanbusan@user.noreply.gitee.com> Date: Mon, 21 Sep 2026 19:14:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=A6=E7=94=9F=E4=BF=A1=E6=81=AF=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlalchemy_fastapi_demo/.dockerignore | 11 ++ sqlalchemy_fastapi_demo/.idea/.gitignore | 10 + .../inspectionProfiles/profiles_settings.xml | 6 + sqlalchemy_fastapi_demo/.idea/misc.xml | 4 + sqlalchemy_fastapi_demo/.idea/modules.xml | 8 + .../.idea/sqlalchemy_fastapi_demo.iml | 17 ++ sqlalchemy_fastapi_demo/Dockerfile | 21 +++ sqlalchemy_fastapi_demo/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 176 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 186 bytes .../__pycache__/database.cpython-310.pyc | Bin 0 -> 628 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 829 bytes .../__pycache__/main.cpython-310.pyc | Bin 0 -> 1558 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 1978 bytes sqlalchemy_fastapi_demo/api/Score.py | 132 +++++++++++++ sqlalchemy_fastapi_demo/api/__init__.py | 0 .../api/__pycache__/Score.cpython-310.pyc | Bin 0 -> 2523 bytes .../api/__pycache__/Score.cpython-312.pyc | Bin 0 -> 3879 bytes .../api/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 180 bytes .../api/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../api/__pycache__/advisors.cpython-310.pyc | Bin 0 -> 2339 bytes .../api/__pycache__/advisors.cpython-312.pyc | Bin 0 -> 3037 bytes .../api/__pycache__/c_lass.cpython-310.pyc | Bin 0 -> 2254 bytes .../api/__pycache__/c_lass.cpython-312.pyc | Bin 0 -> 3363 bytes .../employment_api.cpython-310.pyc | Bin 0 -> 4501 bytes .../employment_api.cpython-312.pyc | Bin 0 -> 6042 bytes .../__pycache__/statistics.cpython-310.pyc | Bin 0 -> 3932 bytes .../api/__pycache__/students.cpython-310.pyc | Bin 0 -> 3050 bytes .../api/__pycache__/students.cpython-312.pyc | Bin 0 -> 4401 bytes .../api/__pycache__/teachers.cpython-310.pyc | Bin 0 -> 3085 bytes .../api/__pycache__/teachers.cpython-312.pyc | Bin 0 -> 4150 bytes sqlalchemy_fastapi_demo/api/advisors.py | 50 +++++ sqlalchemy_fastapi_demo/api/c_lass.py | 73 ++++++++ sqlalchemy_fastapi_demo/api/employment_api.py | 127 +++++++++++++ sqlalchemy_fastapi_demo/api/statistics.py | 106 +++++++++++ sqlalchemy_fastapi_demo/api/students.py | 108 +++++++++++ sqlalchemy_fastapi_demo/api/teachers.py | 81 ++++++++ sqlalchemy_fastapi_demo/dao/Score.py | 56 ++++++ sqlalchemy_fastapi_demo/dao/__init__.py | 0 .../dao/__pycache__/Score.cpython-310.pyc | Bin 0 -> 2291 bytes .../dao/__pycache__/Score.cpython-312.pyc | Bin 0 -> 3555 bytes .../dao/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 180 bytes .../dao/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../dao/__pycache__/c_lass.cpython-310.pyc | Bin 0 -> 1703 bytes .../dao/__pycache__/c_lass.cpython-312.pyc | Bin 0 -> 2454 bytes .../__pycache__/employment.cpython-310.pyc | Bin 0 -> 4525 bytes .../__pycache__/employment.cpython-312.pyc | Bin 0 -> 7213 bytes .../__pycache__/statistics.cpython-310.pyc | Bin 0 -> 4637 bytes .../__pycache__/students_dao.cpython-310.pyc | Bin 0 -> 3938 bytes .../__pycache__/students_dao.cpython-312.pyc | Bin 0 -> 5460 bytes .../__pycache__/teachers_dao.cpython-310.pyc | Bin 0 -> 3176 bytes .../__pycache__/teachers_dao.cpython-312.pyc | Bin 0 -> 4139 bytes .../dao/advisor/.___init__.py | Bin 0 -> 4096 bytes sqlalchemy_fastapi_demo/dao/advisor/._crud.py | Bin 0 -> 4096 bytes .../dao/advisor/._service.py | Bin 0 -> 4096 bytes .../dao/advisor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 188 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 198 bytes .../advisor/__pycache__/crud.cpython-310.pyc | Bin 0 -> 1862 bytes .../advisor/__pycache__/crud.cpython-312.pyc | Bin 0 -> 2844 bytes .../__pycache__/service.cpython-310.pyc | Bin 0 -> 1349 bytes .../__pycache__/service.cpython-312.pyc | Bin 0 -> 1597 bytes sqlalchemy_fastapi_demo/dao/advisor/crud.py | 56 ++++++ .../dao/advisor/service.py | 41 ++++ sqlalchemy_fastapi_demo/dao/c_lass.py | 66 +++++++ sqlalchemy_fastapi_demo/dao/employment.py | 175 ++++++++++++++++++ sqlalchemy_fastapi_demo/dao/statistics.py | 110 +++++++++++ sqlalchemy_fastapi_demo/dao/students_dao.py | 115 ++++++++++++ sqlalchemy_fastapi_demo/dao/teachers_dao.py | 67 +++++++ sqlalchemy_fastapi_demo/database.py | 24 +++ sqlalchemy_fastapi_demo/main.py | 49 +++++ sqlalchemy_fastapi_demo/model/Score.py | 18 ++ .../model/__pycache__/Score.cpython-310.pyc | Bin 0 -> 738 bytes .../model/__pycache__/Score.cpython-312.pyc | Bin 0 -> 869 bytes .../__pycache__/advisors.cpython-310.pyc | Bin 0 -> 786 bytes .../__pycache__/advisors.cpython-312.pyc | Bin 0 -> 1081 bytes .../model/__pycache__/c_lass.cpython-310.pyc | Bin 0 -> 813 bytes .../model/__pycache__/c_lass.cpython-312.pyc | Bin 0 -> 882 bytes .../__pycache__/employment.cpython-310.pyc | Bin 0 -> 1096 bytes .../__pycache__/employment.cpython-312.pyc | Bin 0 -> 1462 bytes .../__pycache__/students.cpython-310.pyc | Bin 0 -> 1408 bytes .../__pycache__/students.cpython-312.pyc | Bin 0 -> 2282 bytes .../__pycache__/teachers.cpython-310.pyc | Bin 0 -> 1170 bytes .../__pycache__/teachers.cpython-312.pyc | Bin 0 -> 1455 bytes sqlalchemy_fastapi_demo/model/advisors.py | 14 ++ sqlalchemy_fastapi_demo/model/c_lass.py | 23 +++ sqlalchemy_fastapi_demo/model/employment.py | 20 ++ sqlalchemy_fastapi_demo/model/students.py | 41 ++++ sqlalchemy_fastapi_demo/model/teachers.py | 16 ++ sqlalchemy_fastapi_demo/requirements.txt | 5 + sqlalchemy_fastapi_demo/scheme/Score.py | 15 ++ .../scheme/__pycache__/Score.cpython-310.pyc | Bin 0 -> 902 bytes .../scheme/__pycache__/Score.cpython-312.pyc | Bin 0 -> 1174 bytes .../__pycache__/advisors.cpython-310.pyc | Bin 0 -> 1010 bytes .../__pycache__/advisors.cpython-312.pyc | Bin 0 -> 1221 bytes .../scheme/__pycache__/c_lass.cpython-310.pyc | Bin 0 -> 1167 bytes .../scheme/__pycache__/c_lass.cpython-312.pyc | Bin 0 -> 1469 bytes .../__pycache__/employment.cpython-310.pyc | Bin 0 -> 3019 bytes .../__pycache__/employment.cpython-312.pyc | Bin 0 -> 3662 bytes .../__pycache__/statistics.cpython-310.pyc | Bin 0 -> 2046 bytes .../__pycache__/students.cpython-310.pyc | Bin 0 -> 2167 bytes .../__pycache__/students.cpython-312.pyc | Bin 0 -> 4293 bytes .../__pycache__/teachers.cpython-310.pyc | Bin 0 -> 2249 bytes .../__pycache__/teachers.cpython-312.pyc | Bin 0 -> 1896 bytes sqlalchemy_fastapi_demo/scheme/advisors.py | 12 ++ sqlalchemy_fastapi_demo/scheme/c_lass.py | 34 ++++ sqlalchemy_fastapi_demo/scheme/employment.py | 65 +++++++ sqlalchemy_fastapi_demo/scheme/statistics.py | 36 ++++ sqlalchemy_fastapi_demo/scheme/students.py | 58 ++++++ sqlalchemy_fastapi_demo/scheme/teachers.py | 52 ++++++ 110 files changed, 1922 insertions(+) create mode 100644 sqlalchemy_fastapi_demo/.dockerignore create mode 100644 sqlalchemy_fastapi_demo/.idea/.gitignore create mode 100644 sqlalchemy_fastapi_demo/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 sqlalchemy_fastapi_demo/.idea/misc.xml create mode 100644 sqlalchemy_fastapi_demo/.idea/modules.xml create mode 100644 sqlalchemy_fastapi_demo/.idea/sqlalchemy_fastapi_demo.iml create mode 100644 sqlalchemy_fastapi_demo/Dockerfile create mode 100644 sqlalchemy_fastapi_demo/__init__.py create mode 100644 sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/__pycache__/database.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/__pycache__/database.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/__pycache__/main.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/__pycache__/main.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/Score.py create mode 100644 sqlalchemy_fastapi_demo/api/__init__.py create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/Score.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/Score.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/__init__.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/__init__.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/c_lass.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/c_lass.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/employment_api.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/employment_api.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/statistics.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/students.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/students.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/teachers.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/api/__pycache__/teachers.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/api/advisors.py create mode 100644 sqlalchemy_fastapi_demo/api/c_lass.py create mode 100644 sqlalchemy_fastapi_demo/api/employment_api.py create mode 100644 sqlalchemy_fastapi_demo/api/statistics.py create mode 100644 sqlalchemy_fastapi_demo/api/students.py create mode 100644 sqlalchemy_fastapi_demo/api/teachers.py create mode 100644 sqlalchemy_fastapi_demo/dao/Score.py create mode 100644 sqlalchemy_fastapi_demo/dao/__init__.py create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/__init__.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/__init__.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/c_lass.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/c_lass.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/statistics.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/.___init__.py create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/._crud.py create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/._service.py create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__init__.py create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/service.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/__pycache__/service.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/crud.py create mode 100644 sqlalchemy_fastapi_demo/dao/advisor/service.py create mode 100644 sqlalchemy_fastapi_demo/dao/c_lass.py create mode 100644 sqlalchemy_fastapi_demo/dao/employment.py create mode 100644 sqlalchemy_fastapi_demo/dao/statistics.py create mode 100644 sqlalchemy_fastapi_demo/dao/students_dao.py create mode 100644 sqlalchemy_fastapi_demo/dao/teachers_dao.py create mode 100644 sqlalchemy_fastapi_demo/database.py create mode 100644 sqlalchemy_fastapi_demo/main.py create mode 100644 sqlalchemy_fastapi_demo/model/Score.py create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/employment.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/employment.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/students.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/students.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/model/advisors.py create mode 100644 sqlalchemy_fastapi_demo/model/c_lass.py create mode 100644 sqlalchemy_fastapi_demo/model/employment.py create mode 100644 sqlalchemy_fastapi_demo/model/students.py create mode 100644 sqlalchemy_fastapi_demo/model/teachers.py create mode 100644 sqlalchemy_fastapi_demo/requirements.txt create mode 100644 sqlalchemy_fastapi_demo/scheme/Score.py create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/Score.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/Score.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/advisors.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/advisors.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/c_lass.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/c_lass.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/statistics.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-310.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-312.pyc create mode 100644 sqlalchemy_fastapi_demo/scheme/advisors.py create mode 100644 sqlalchemy_fastapi_demo/scheme/c_lass.py create mode 100644 sqlalchemy_fastapi_demo/scheme/employment.py create mode 100644 sqlalchemy_fastapi_demo/scheme/statistics.py create mode 100644 sqlalchemy_fastapi_demo/scheme/students.py create mode 100644 sqlalchemy_fastapi_demo/scheme/teachers.py diff --git a/sqlalchemy_fastapi_demo/.dockerignore b/sqlalchemy_fastapi_demo/.dockerignore new file mode 100644 index 0000000..01b463a --- /dev/null +++ b/sqlalchemy_fastapi_demo/.dockerignore @@ -0,0 +1,11 @@ +.venv +venv +__pycache__ +*.pyc +*.pyo +.git +.idea +.vscode +*.sqlite3 +*.db +.env \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/.idea/.gitignore b/sqlalchemy_fastapi_demo/.idea/.gitignore new file mode 100644 index 0000000..f6906f2 --- /dev/null +++ b/sqlalchemy_fastapi_demo/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/sqlalchemy_fastapi_demo/.idea/inspectionProfiles/profiles_settings.xml b/sqlalchemy_fastapi_demo/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/sqlalchemy_fastapi_demo/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/.idea/misc.xml b/sqlalchemy_fastapi_demo/.idea/misc.xml new file mode 100644 index 0000000..959f330 --- /dev/null +++ b/sqlalchemy_fastapi_demo/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/.idea/modules.xml b/sqlalchemy_fastapi_demo/.idea/modules.xml new file mode 100644 index 0000000..724d6c7 --- /dev/null +++ b/sqlalchemy_fastapi_demo/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/.idea/sqlalchemy_fastapi_demo.iml b/sqlalchemy_fastapi_demo/.idea/sqlalchemy_fastapi_demo.iml new file mode 100644 index 0000000..afc0918 --- /dev/null +++ b/sqlalchemy_fastapi_demo/.idea/sqlalchemy_fastapi_demo.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/Dockerfile b/sqlalchemy_fastapi_demo/Dockerfile new file mode 100644 index 0000000..ce91c5b --- /dev/null +++ b/sqlalchemy_fastapi_demo/Dockerfile @@ -0,0 +1,21 @@ +# 1. 使用官方的 Python 轻量级基础镜像 +FROM python:3.11-slim + +# 2. 设置容器内的工作目录 +WORKDIR /app + +# 3. 复制依赖文件到工作目录 +COPY requirements.txt . + +# 4. 安装依赖 (使用清华源可加速,不需要可去掉 -i 参数) +RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple + +# 5. 复制当前目录下的所有代码到容器工作目录 +COPY . . + +# 6. 暴露 FastAPI 默认端口 (根据你的项目实际端口调整) +EXPOSE 8000 + +# 7. 启动命令。假设你的入口文件是 main.py,FastAPI 实例名为 app +# 注意:必须是 0.0.0.0,不能是 127.0.0.1,否则容器外无法访问 +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/__init__.py b/sqlalchemy_fastapi_demo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-310.pyc b/sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e85fdda0258a3623698fb0dabe7c64d36c64ba7 GIT binary patch literal 176 zcmd1j<>g`k0{@-MvOx4>5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_;vsFxJacWU< zOn7EqN`859Oh9FFMq*KJKv8~HYH|sPUy_lZ2jyDC6c^?s<|JpN=2ph1B^H+?7G%b! lq~_+w#K&jmWtPOp>lIYq;;_lhPbtkwwF6mJ%mgG@7yuyQE;j%G literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-312.pyc b/sqlalchemy_fastapi_demo/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2156533777a06ea013d42ffa38231ba298283162 GIT binary patch literal 186 zcmX@j%ge<81pYghWr66&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd8U`fvLyJ?3iuE&- zQ_C~+^j%VmvrF;|^q*~Nel~CV)3wW<>|CIqmRMYpSdgh(P?VpQnp~n^T$q!Xlbn&7 zTNw|Picd++&DW2Q&&85r~UHjE~HWjEqIhKo$Vf Coi#H6 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/__pycache__/database.cpython-310.pyc b/sqlalchemy_fastapi_demo/__pycache__/database.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b4f693443f66ecb36663fe60b862be292bcd679 GIT binary patch literal 628 zcmYjO&2AGh5FYPeHzA37DZD}>P(z`Bh$_^ywCW*Lg{4%iBCVXY+ugE`gY6KdDiSDM zc?Y<`8}KZ?a^e*@F;0PYq#1wTSep4}MmC#uK>M-x?QAsw`02=X3z2N0>wOFi7^y&z zln{r#$`gL-iy#e<`)SAt59cI}xX%I>@Q8(<{d9>3b4X(rv87Lt)>xcCyY>sKL7UiS zt~fP32Xs&fBM}ofL$}TgWS5#3`zT?@DYJPr4%=Fvp_IS2R1Xekc|nypRPv1H#&J`~(O>##fP>O1FSwXxCsZ3cE;Gi3958CATgKXW zW}{PXGB#XsqTMCE4-xT5Om2FriS(ddxAm(!%EO#(T_x6}63WM_An zpS{kW_Fne3d&zEg^rCO0%L6I5ARBCB^F{f^VAn#!eaD+ZvPs3CxQ*%-hK9dPf*|%= IUgR~xKUD&x6951J literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/__pycache__/database.cpython-312.pyc b/sqlalchemy_fastapi_demo/__pycache__/database.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce53fe40cacfab8b30573deec1ebcd25671d4d75 GIT binary patch literal 829 zcmah{O=uHA6n?XR*{n@ktu;tNgyJC-vnU8{5jC}~g+@VZ3*Ce3W_Q|dyPHjBHm;Eh zK|T0`3LflD3W6fF7eUaQcQ1u{&_z&Di{2`s(1QnOlPx_uFyFlQ=FOY;eZ2RnlmcuG zTz)=xCJFF8a<-Qk8;wiMSOg0!B3SX5Y!3v03^-2yFHOJwEWQ7ntXlu5ARV;z@f>=Mp$VH?Gi+Fr>u<}nF7 zENnUkF?{<9){6$k*LvL=tvJ2qTJs!GRpNR6KqaUIM~+s4+$qO14QJM)zFG-JvV5o* zRo^o`*R}mH8QIfLmClAj(JonL+*tDv81}H;@EME&ViNcC9Ne5_s7_E! zsA`)yuuJL?rt`j6R@YzMTz|6obLH8Ow@d1@L4BiaA1)Jb4x7HpL^B+77P~b)zS1r1 zda7mkMkH*mTnnWc?CVyMq}dn!Y||`*U$9k&&&jTP2kL_x94~f$On2Oszskx(`Hp;F z*}BcOjK6d*%f7Lz4?Pfi;L+|r^mNZL{x#pnXeptx^FN7H3)4G+oJU*|$xosY3^U{B z3;Dw7(c!aG`cVF2elR~itWR7hgi>orNHoHsFvyy2cKQMuEC3`Gh2`U}XH^}1g6v~% zq!>NPV1q{pZB8OUhrU4nh6LTCXcaPlBv3M|ncP}ZtxKQUyO*kO#CIbf+Q;f`-x8U% P#QwU_kVVu${Wht1R7 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/__pycache__/main.cpython-310.pyc b/sqlalchemy_fastapi_demo/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3490d0f6cdb8193e0aee30ee05b2a80dca1e03ee GIT binary patch literal 1558 zcmZ`(TW=dh6yBS?YsYpH+fCZKr4Cma#HQ{8mkJ?D5fV~q0|6neEG?6rX}o4HW@eob zKT(9Lyjb)BsR)TyegTTqlnMz|M1ub@uhe$)7r2QtyX#O3bw?h3=bUfOocZQ>!eTKm z!S~gNKXl}rB>gUohd&*R*WkxCWJ$sjmOaUrEm;;=@f2UR)EKLt=4Y%-j5ROo>z3{t zmJ!<-FX!j2xfo}?f?u?XG1dW>tWwIE2hKu@7Xg=JYyhWXRb+`6ooeR@(Q$47yAv7b z@f^8DFV$3@_p3 z8Q%gvijU2B%J?|0&3G!1>jXYIni6@RLyQ zQv(f7y0RYs8c!bx^&2wR-$X1rxAqpm()mm8uD|VK?2&Cm33&1>LXpcN*I^BXXGyT> z283&`BPOC*8ulVW#Y*CLy>Q1TL1d$@3!con6UHfwh#;p;C*!wuW^ zksH|d#l9iHS=8xMLfmLXnc@^Gd ziCu)LAj41=;<=#2LoUfmR*}WX{;lbXtO3$sWdAJZs%lj(!>GbA3?q&u-27kKKmP*O CiU*!1ULZiYxjT3DPJhCtX1W+F_-rc2*kjy?}?-CeKVT|xT7 zfSQeWVq$_Zk&QQw1vZ@~1|`uyz?d9n3C&}OOQfy5tJ(Cm&vVzK{+J2(;(0#b`+mN^ zzj=NL1bl#eSJJmKKe_?c(*S&5UKDW~j8 zxlEap+_ER-HL+9j$qlIn6T1lZr~EZefN+8}+(@v;#BRa~r9uoquFOe0mHM6OtYaG? z=cZ?au_OjK0AipQ`e4JRe}lFDrXnbkiQD}8jaV3%W?;}f3EFJjaN2%|MR%QPBjkl4 z*hH9N+c(Md@yv!y$hNBAFan=AlC?kcT;0k>@EB}9l64Ta!03^f9(WwK9*G%xY&~u8 z$$we5z^ATu0id>#EoqmcsVJF9G;_+Xp?<>-7=tHZaP#B_XZ>ZseEWQR{OJQK#u@A$ z5j1`Hweti9&t14UF(yJNp*cZCaR+vx?6jCgm^&+Ih%j8LlGl++xk%1Q%DjxSIxplz z^2a%mR)`UUJvtK7Gf344<|f4~%%32kYGGpCv5D7T9hL||o{yE5u9fb+TVDOTy!w9r z8Nw>v`K@?ygmquT{R>`U|}dgCm1 z>Y^?o+yIf5R>hnyDp~BFCBZ3Rp1l<3a6phGWsX-=k<_B$CQD4K2$JMQLDFo7jPw}= z9*Q$afW%S3olNtRplSIqNzlr|O3liJwkfBgDe-O0>B6*Dh$KlvlKgP)t96*IU7`hv#KM%<}wr!9&4|LN15Bl9Cpr8Aa2@a~)(|SjU{ENwQ}u zeIHa8<@$)vgw=hOzLnUYrjy{UHN-3p>7i_|sibVpYL|wCHDr_hRBQK2rEfC!kckU4 zEcTIg5OlWckbY%Bw46<@dk2nXI*pEaJwM91HwfvT#Pg?cNUvl zt(ywf2Earf0T<(_h7Xy`1M6O+f6O>DZh-K8aNz-9Ef>p!yOFM)NSDz!VvJ83V`)$<`9c4KJ57`$W}U9Kx$xY=!-K5sn#im4c_E6$kShK#ds z7{hOx$}80n;QUL4pV;F+lXAGmg_p07E{+yG;bI_K3^WxRBY%3GPFK|lxK=em`uP`3 CnZL7HmApPJc7=&F%ZX z->>CVDyhJCz?dx_-lQmhiB9JyX5WDy{}3q(Q3!Gr7g@-~7Isxjbu~*vVjMfVYgmSi zRVU`gt+Oc^%QY?2O<5_VQ0;U2R0vc0EhGxh{_;pib%pg6a_o99QSsUdpePol|CB!1K8F2k8*eztM#C8L= z2Tt6!2D_b_a!-xyAg@SVFW~w}AKAGEx4h?env(c9*+q6s{3gI}2K=7?#E19YOZG`@ zKiNO5WM6Fyp0k>-e_W-k=EsiF3M~=tr`|ttV(8to1zPd!a>-8|8T#OOx$04tMSg6U zat@;q#)k`KMvoo&2x4QLdO0$h#eSC@J<4d_qfzH%g+S*iI#lh31Dm(*w&uQVUYTm% zywbdU?eU{ou`REYvI!4uP?UlKL~!m-n{+*_Qm6{9ihCyY*4CYZ=OPF7o;V|_4V z8C>wiXBD;?x=&9WeRJd_r;Lw$VwXty3?CV)6(;h`9b)AoEqJ2uO_WPf_l*&L+Q~bG z3F_8zV|ni7D|U`hw>$#Dh$MZWQuCAI`0$`EIE5R~;HiwEA+`m=PkRoX<6bpqlgUHp z=-Iq0q7GSt#`VRAKZdgSMu_xd5paE$_QBSIrP~opGm;~o@i0LI6SaXqLy|LXussc$ zRX4zb;NEwSr*ADjYy|hd3~v4~3*LcOc~zb(lnM0>LcP50WYv(@gm~C!4erZ?K(iX# z3V+x((Fl5dUA|g!8#clbzFa0}1c-}jf~V3zhlzlaz0j4f4=&#b9{n2LD11HJ19Jro z&GIKavEqvf=tM6@b)|@B@FcEdc(K~?VqDaSb_%m?ouj~#UYBcNoe?s{4gx}lsvwyH zL`)!HPpz(j(_({cJDm4Kq)%(^?hC}R9Wcx?(Ad`mw+A5Vd`U3>Q^@e&zkSh~n-4x; zXkTgscN)$4N5R$G*?7orw_V~Duw5<`Jy$KA4jC3~`$?OF*&OOo!gj%ce?C`HV|eAR?zap8V*`j^FpndbSqg1GkbClXU6g3RdS5JbwUbu5(wme(o=3TSmz z>vzB#=qVE z>Q3i1*Uxfs>i=aq(THv%;KPXc5N?!w_^QjtrB1wMKNd9r59D&=b; z*O>6SuYyOUf}%!>oRp95pi2CIVY2+i-*U^O>d?2LFetnTO}|VVumLi#shT*A45Te# tg#W=9KgX)MWF`#lg^?~p)t-kK^SRk==-RW@6?h42<}>rXwW~5q{{oCM!4Uue literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/Score.cpython-312.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/Score.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebb333c4204e2065aef66773aee8546f68c9e49c GIT binary patch literal 3879 zcmc&%ZA@F&89w)3-|KH{jg^w!xhm|EqwhmVU?DDd(Zu_4T3HE zwIlg_yyyKm_kExDJ;#5s+bsy%Ul%_gJ7PuXA9SHNWd{~JP8Om2NJJtNK~cufFm%pF z*eK`cq6WVq%KQ1K;1?7+7coXnev>jcM9fi(-=fUDA zVP3Q8cVg$*EBXPdqiCFG)D>`ZU>%931@k;tL$ioh(I(m#9P@?>)qrif+$bm3VVCHH zUp+RB3ZmijSNkFA4hC?xe zFP{4`%!L~`5fDebtZY@N7YGg}u(r4!7wLlWC0$^A^Q%8>KEAW@tM@m5zqt0NkJdk0 z1S$3gFsnyWjBbg*xkb^l^=IgkO;qsly|rI|0)p!wr`LY>MOB<54%n922qtxOVvxqe zahZ>Vqv3?iiX$Nnaj=IF55M=|w{sS{w-Ez5lF(3!&=};*-j-rhD8(!=I&P=A6gP|> zaFdLe9rCio0|KN0I+&Ybkd4$A!AQhwsP2(Qx+6%`W0FL%-U02~pTNX-UBX22g+q8U zJmI^DrSU{8?py!zz4cG-uRZwu+1FX$Xi!Q7Bp3<(6i255+Ezfs z(U=c-e2V*f;#0DP9z!)qTEUJDeo`lNo9JI@^iLbIc}mvSg0(esK6`DkVaa+r-M?(D zPygtJa=w|?!_3bbeeX(%WFRa~``*R3g3&;Xh?q>nhbUCpQYG&1WIxz@c_-JpSh6Q* zsFWr$BD=uNYr&aeDgiJIZQX<5C282fR~z>}efH>swFjBCk8^VXMetf8DFs3?5zB&z z6TxuA%c(&!Q}2vS!KV=cgy#&T4F+DQVO5cZ0cd6A~ zva}T}ZJDdt#+;>SIhnq+Vs)-MT60{!_tKK1KW_pbJJXk6>`=us-fo5*gGs0scNK&} z*?l?ZF)1`g_3df8!=~933+^=P+k4$vgMX9GQyo(WXa}46T~lR7wIL+CZ5nDrSYwj{ zb5El-E2lT43|hYNL!=!z)iUz%vpo?f9dwUoqPnqucXs2Cb8BCHsRF`lR3q;SPe^gd zqJWCwKyu=y8heTZLa#9e1+pa`le7f#@=BCcV0iGYu#^Z-+z5<9GKX(W1jg}{?5I!` zc*y1nJgH?LjVI0a4i!W8kWw4<)a-%Xqwtd^q0@2HaeLsv*75=9?f1aI=a(?%T`a`;CUg@PoFu@o;NU|S{zZbQY&X)7Kt3Kl@$y? zXj(`KyR+fjy@;=rKs6!g)ww4jHh(+6_Ca>z zUd}5hIiaGS`mS09Wpg~K!{1mXR}+Dp0DhSX%FKvFON#>W3dobnov(wu7xw8hMp}SQ z1-TP>+A82ZzSvT9_W@+B&ATD{)M&etnn`8&Qd3uqyJ~S&YHY(7ZNF*D;Zo1p zLeJTv<;}ayiq$sTdB5uyU77EF+V{)8e0^8$2M_z^`X2G6GXsS)1Nqkn|5iV^>T1tj z$e+2o6xg-KeL<5v-@150Nu(W5{Y=7>JqUBWWouyR{ z_0A%%f$WgCRp#SUVk|`Hvr0B_-E2!$?vJWy{d4xB?fKtig6O?}arn2g}Fq#tNdC6SbdzRWQU^8~eQ zpuQsNdxDNWL8qRelYd8p-&ou~?@pV`0%EOq4&Od}S1K~@Z=4OY!OXdQ_nS-3AFk9l z&Pth^+2Q=DD@*n7thkyp$3OIK8wJL-Y_XR)7@t}lWgbS*Vs<{KJ3Aa=J!O{CT$<*5 z-D^drYukhl9m$M-7~3|QnEGX>yUfA()N`oJ!w3rOp67IjD)5$BN^7JFj@&*n%M}^V zwxG-NcBWz3(Ol+Wd}?z)r)w(JP-bCP?$~YCqKlcGj9oDcqhc0DFk9DBHqx1i9)R*_ g2cWbrP*q~;3rv09^?H%%{$IY~#5Vl~atR{wZ@}A)xBvhE literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/__init__.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8898a44f831b6186ab385aa7beb2ca3d9ef4120 GIT binary patch literal 180 zcmd1j<>g`kf=^7#vOx4>5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_`vsFxJacWU< zOn7EqN`859Oh9FFMq*KJKv8~HYH|sPUy_lZ2jyDC6c^?s<|JpN=2ph1B^H+?7G%b! oq~_+w02wjy@tJv|CIqmRMYpSdgh(P?VpQnp~n^T$q!Xlbn&7 zTNw|Picd++&DRI2(T|VM%*!l^kJl@xyv1RYo1apelWJGQ3bcq3h>JmtkIamWj77{q F767#^HjDrO literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec1265a8d8359f6886fa2b39c520558b86f5ddf7 GIT binary patch literal 2339 zcmaJ?TW=dh6yBL#du?a!I`^a(NXr9QLdgpfQiTwuY1K%`jYy(OD@)eaGi@BaUNgH} zXmKT=6)HuMDp5gO0&P)?8c?~Z5|KdgKjwiK>Rg_9fft@QXLdJnNW)q?J~MO9T)y+2 zZ@qjzr@`}kWqILqu>QbK_mhFnEAaX+5KUtmBMr?ZHgTyoZzF8D%;%7U}z>lqxUlq5u)X z!X^*R#&uxL--Bq~{dMEhZ`a>_ud{OH@ycT7;f>DHgJmjv{J;r9zgmNH$~5DFQ*V@X zfuytxK6gZIz8arb;L%FP*6M0AJ1Y{0Wli8#|C~B{xH1RG_?1)jCiC9%E7Rv|^Nw(* zg}1oJMV)yXUKC95_&`US-_%DqvLN&HeG#d1)cM$!=NL%E$63 z(hM<(MZ_?4AP0@QAJiz=$%8hYT|tTfDM(2hs%en|Luk1~Bj6A-u+{DJxK6T}52H94 zx#2Cm0y7{B(d`nTy4VrZWfZ((rqmKInc_ltBEnFii9m`2(4gTXfkz;%7RitzHHex4 zB*PX1BzH&eIK*|Mw*$MuK;MDgK^S`yc2EXe)r7Z@+49NR>hY6vv?VjJc9L1?-umj)UhfH4!k8QnB2 z!C02%wrI$D+LT#KNXGnTl_`088un8tie9vkcD8lm$V_!+c5d=md3Hu1|3ZXryLNrF z{@ab!r4Ks~zgoL~dkfkSSM6N6vvKp@>XmDqtG7{}T@Z8UEVr`}6rjG4)F=b-$dj}U zvkoEu3;rSSDZ%R_5&B~A6l=AjmldKo?&(OI&7Nf-hp&;4g#1X#N;91DXYOUW8v- Wx5)FPm^wtP^nPOH_LGb`M*am5!Bz(V literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-312.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/advisors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5253574748f6d326e9f0ace00c2380a2ce46eece GIT binary patch literal 3037 zcmbVOYitx%6u$G=*X-`J^g(MM3KXcTp`)})B#1#lC?u6ogs?H$EPF3@>%P3R3k6Hk z`m6!tAJT#nvl<~KEx0@)RZ&U&gW=CMG@(o+{II*0Ulbeud+t28yI4e+WbU4sd+vA6 z{mysK>{YKu8rI8;LShC@UXLo|gC*c3{F7*J$N z)I>a{l0Y<$Nu)#b1Pz2hEEpx4EzuQ^5sk;YLqgFmZD6zK+3he4p`@uBgt|>l75SoG zz8Cd!quhvza8T$K`uSd=6D1jreqkO9qoSqA_c@=fz*GBK;h3_XsP81>2_=8-gZx)Rxzi`7en=~O zf)G6sUXh^jZW2l=>bsF(B-BNs`vc}w0F!830UyOoLTyRx*F3BeR#aLC!CY{w&%w}# zrsRt2^5SuMae716?|lvQB3P$Qj1l@%J8qpSmHo?>VEB)no}Rcl~? z{khAoyBo*djp>R^!{rSV?#)?oGp&cY0}dqw%p{2>S&9tDLdEi81=2;h4UC6wit9xn zL38~{pi{YoXy|puSWsSkvE~$bWh$fBeVX=NEGq&rN?bl0QG3`}i=e zf=M8QwS7%ClD9}Qx2nV5K&|kpJ>RelU~! z_U!b96L&6sVVv&5xxRDhaDHI$KE`t&eLwZnpy~PZuYVmGE@j`?y~VI~*!8e_0xT8H zm9iWPhh3K}UB+@`Lj&A}lUP)PE1M_eo%2>H9>qp*bjdp5$w*~kl zYl51jdPmnp)&%wDr-_L;nCygWLLvoD;aE}^8~b80wdf3(Q*3y?? z8T28freK^AIF7r8TE|iAO|;}DYQ2TpZ=p4J?MSLTRNrTx%yT-Ll zHa|Po_WP=A=dP=-+(ja{i8~rfFFn>ZquZIL3_km`VP9VLxBhNcK)f=;GuIgj@lF%2 zZCDy_YGs&hrI;MIrGUw73zOLlll?Nx7iM^7&UhGReSiJHu5@=_{Wb3S8?CFyUOca7 z2S{O-%@%H0&&F7}l4S!ct!%QMC7EYfCNJN3wf)NS-xRj79&>3AmuY1XJ=|C`+fa`l pd@Y0MF(DfJ8?$B0u5rt6tZ2*Z7ztRs7(AqR&hgNESLZ=5%Rjj_@)rOA literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/c_lass.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/c_lass.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6f1bd03728452e2a7ae92140fd7cb7f01e41292 GIT binary patch literal 2254 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 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/statistics.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/statistics.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab56b072df6fda43c18f2acfb21543ba92106d0e GIT binary patch literal 3932 zcma)9-BTRL5#O2pxVz=<009z67$HE2mCzyiORjQIN=EMPz2krgB}YwfPtSBuPxo)8hon?;4fyGQ z??0UwG>m^?=lHJ(oll`D!3{$gf<;Emd=_(`$EI&Gl<~-lZQmx|jGQ><=ZLqWd|dDg zvFp3>fIkoy{bF45OL5sR)3_ZC#zX!PGeWj!_`_hyiO$6%{s@icqS1KFA0s{=osTd0 z7vgb$oce`mBEINfB;Ey&F8P;w9>tUXB*~9^b+i(!F%Z2IPx({vW&d(K?N7&7{44Q{ zKNHXTv+0!=vT#zAL|F{J;J^*-VZTp#2>hlkhQn*(T(}@cpp8Ns z3++u;oEH~m#orujE$ z{*~_h88J(~&B4x&YntLJXwG-F9dS)8koF>Jd!&6`+z^YPo%zMZP1pzeZi$LmqS-fT z_AQ!yTV!kXX1{yn*?Z!Bnq8sUAHeLBJN;1Hq46ae|J8quefBI*E3iV*W59*ng3+lpav%d^OlewqaLUXEUfr+6}h1s?=B7O_OF-1yLY(bO8)j!)>sx z3z;>T*e)&g)>(peD(&%=#p&h6=}#7?SD-CJ+X&NVVThp}5TUBcIz@U_^Q5T@pi|ur zqE@JL$j0?XmkFM0E;ed5rmp+T!58nA`_R;HfVADz=vW=2!#ccU?%BKcW1}%@87bSD zV#cn+jCMZdf~981*<*sg;D2KRyLJ7PXZY~lF8GsmSR7Bk~F&AJL~HED2QrL!g!~;30Mi5^{NQtWF46GJ{T&^ z9qlehfQ(uaH&-TcUqe6~gIm@si)DZAtM(ik=p`J1RauUbS`eufV0!AFCC5NnyWe4A zA4-|X44bA(rI(XaFeoo0nMQI2$qW!}N!XEQA?-CIizpvDz3M1P)j1&C8f9fR#PWaT zuN}@U=aqaH#O;wKiesn%ojt^#NFk;Z(}-C533CZZA{^|qRgcN@AlYZ+)oEu&(V5ey zX%@{8EV%p-csv$(ywnn%uLA)xOeUN}9)-QLS8p_1X${qSKRn0S$gOc;z%2%j@m+wi z-~d6mOyJ%_s>{`8CSV3O6E0;e!<} zLT(*eaM!qpS?G^!t207B0cwEd-=cktx@N(tjB1K`-_Tu{rSd>r(_x%DhZ0Y7dvGZ{ zdQdDuJwCvis9EDgbn)CGd~Z-md@>lEI#=XPzurH9c?!+C zTz&_i_V95(=pAt420DJD%J*=Q?z)$d{{YFU1xp0E-lKxxN%($@tBoCB?dZAj|E-Ai z>y0a(!xb}Qq9vg)Bn`p^E&B)1@^0%~w@ymjd;ekOm;0r(lE_$M7JRoalnx5KzTiZ` zttc$QVWnS=Bwp7N(=7`~FlllC2?9<}pJhk{X|Ms0Ls`OU4uBa>oIiio^cWs75iCm& zSS8D#;qHcb3qQH&fME|YE^uRO03>;1PK=Nv;7xAay)4G zu%PNpwL;?kCh?>Zx+Oskv#(8fXUiqx>W!2h1yq=+KG1zehl`Lc5pWXIe+;37RjN1n zWr$%b3Re)}>N${6qsWSE8kz&G2=9*~8%K^Wu)OV(EPu!ue@%_^L(Yqb`SLi77P-T$ kYz$>Nm!lQy=cAcs@#lQr1z8@ni?8#Ad6u_8)0$+z0Om8of&c&j literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/students.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/students.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de1ed86734b09346e1ebed65ac9069d9ac80d1cc GIT binary patch literal 3050 zcmZ`*U2Gdg5Wd?xpMP?3oHR*O=nu3&Ykm^ofl3G=s)7U(DusfOPLWQIcbi_gv)$b@ zG{u!til87uD-nJK2nbMG9{M8zDnf-m@PZH$5|8@|w&SP12O5~!yK|hv$L}^ z-_AGdYJY!DgXjA{PS5HBqRvjN)Ato4_SvCs$Z-eg`d~b`#y*t_Tc6x`}X@lBn`!%s`jXg5y4q8-tH-X;G^m=-C zvO?_rUG#3HyAgCZ(e3meI^KiVs?7;{uhQF0H|^7k_jT};i>A!(+WW*a)q2RdOh3wM ztU`tCfBe~J_da&0%xa-mt;p2Vb;f6lx=in5LV%=5r1_*LLYa9=X_S1Jw5D0;(kbZW z_JwuID&eEMo+=u$KOXJotQ4~D@VOer;Xpk53=_3#MXeLKafgv)*$(L0eZfw73aI~OQWjYpq zt?>~ME5dG_-~efE!1QhLHfi8Rq#G zXcDvwm{dvRE`(Dwc~>a{J(El;%%cYPk$t!pmLNLlqp+YMa|H|VxfQyH(-VS~c=^Dd zx(&lP(=NT&JaMt8tElR?b>+>|?=(-&U%7O=wQ#=m*3s6P#r8LEwmvmM%2BZaExgM41om(jdOlHb{NeGaY(U0UwLni~Tf@dRiVt7&rPlGg!h6x~9 zN34bwfn=$u`BqTn+ps|&S20O|8##!ab%VMedTzN|p&nAXn7-k{$m}p0!`$t`aXsRA zjUmJocNe&T%$ZrDul}rMGtF;@2_W;!5e`SLOF$Jg`X2|~LqSmp2_@8^<~(@?fPmmr z2_;nwodw9$I%a));Y{oJ#lOCvZ=U_2`SF>riR=UFgmnRNQzk9S!jk6$QIWrLuqUJ3 zsaZG=jwuS$3R0vzza9!B|67L`JOJtf?UFg83_##IhOPqFX8?k_&bNV<30g1)J+onoZJ?K;R#z{j^mc-trSwvumujTM zPNkQQ^niM4+zY6e0qR9rm95_cj0YnAqc;#KXbDxODzhXYr@b`{%mnlZYd_bj5H03VS>SX+X^_ zX4HZ4J3*k1NajlPMNd>YoS8G~RYVO+sJkk2>y?9w4bE^fnNSX=oP2Z~NjXWla5vh= zt!0KCf=kV-Ogs6+s*(uDjtoVk>!!!hTH}}-yTGPEN|QM|gSn9-dB_j=>e07AAY1MQ zh0br#K+V|!pEX1wAi(TYL_s*?YyqMy68sMZw9t_j(bWVO9}8JGK+==a*Km4httz_f zfcdyY+9{Lp`(a$%BGd6j#L*XSV1piUOk$Z|y|BisJm6T_q!rHA07Qv>`umSL_ysr;7^d!>-IAtfx`yc$W!3Nh@fg=~)GAW5*G!rZb2+7=-z hmO-u(ll((cneyQ>KX zxfLW$$d5G4gao(EBu?8DWo%MUI#cMho%CmB+8m!C}(IwT3Zb=Y% zi5ucX;U(*YF*(!#`nH=j>9XjN?2>mQR90xUz}_g)JL#KX^>JXyBKpO8u|eE0**IaT zwVLg-ViVZk2(NCx*<`t6wt;AAE)p{Z$k&ytc z+6E+9hL!-MT7DRl71e%B8xe^^CwE#>!r~xEbpuL9l#)tc@38=@x{cb?M2aXP44S0T>(sJP58?<)fM}s$Bsq@k2AI$3oL%m(GEEW69I1t?CV&*n!WN zA&`QnWQoYZSX6o;mJIeu@);$S4$gn{;`}?;VC{GRG9Da?z(Uip?P-!4mZC~fJ{yn3 zqd%1rBVnT}EJ}$~5XRJ8-jg0teJd9ihJLacObYPI`=Q8DU$`hw^Q_Qa6uR>Vr?_ch zPwvQVyXOwyl4lFMPR#Hp3-*(D_@-IDv&eVmpO_k+;d^t3OHNRJ$-<*GQ3JAuWmQ<%G$x#y12)-!7q($V%;wMmKnxI(t_-gq# z@4&?Qw{zv+UtgZilC99KGI5D)L%|}SiKSI*JeG(lEBJ?yz6kFF+|{!b{ZJeP?$FhE zi#!~lZm=)V0p=)hAOLzu7Zf0C1n`&$ActYgz>L};!_`#>%Xl2n!K4EO)rnJKhK7F+ zw6wu1qazlm|J7X3RTR1a-@boXXN3OTk&@G&JNA{P=~7D@4Tt#xs0ZGSM$JbGEomD^ zDm~Q3=`01?Hgt?KSw=P=KSpGi57Z?(%NU?o5fmh}&hJK$zC;?qL7KmO^X{$J$~VT! zZ|4cRGr($)kyadzo`DAKRA}=zL4%C3qJ~d{3EHrBwlt)6z!=QP^5anGNYzoo##z3r z$am!jZ*7?259AKtcKQsm9-86%3-*4Eng(!zZu-3ULLw7aVsOZlVhn@u=uy>eI_NeX^tF^NJHiGU!4dfAWNk!etkS2sV>gUMUGhOFba(hP zck~qbo|0QAc^gaq7W^0dB~QZ_Zcb>*9bV!omw$Z+Z4W|@LuX{P9JcnEZiQ&^P)=Bt zS5`p3Dz9YeVY9{(WSI`opl83BXk@-${Q2%*-_qOkEC@%lcB)kt zavo$bjCae2S7VXN>kg{rIZh`R>`2dZq#YzUO{wHiJQh`mcFGZ9jamk`d@Ge`wAu$_ zj=(Fw424cBevOpmTt%V^N7;R|wx*)3sbJf7$KN*V4;KBwDQ4;iv%3xzcO9Dc_g}W( zcKXNc?+U*X^1J`twBwF%Q~v3~-q4Ki`GV{DyS1ct^49K8x@P!OMq2wy#&ushSa;Ax zFa8U}08Q|+x^~?CG4wnXIU(-WXtFx$t|I4%o`@`~-D(6@m4|DYq)1g~d@aVpRU;FP z!Uc0>ob|1ororC}%l`?yGUg?7kk!&XlkcDAcdij+=bVBOVmkwLV3TSy?jZyNJHe!+ zEs7wLD!+VR=}D0U!I-0R%19b+MFg2n9N5yaJZ#0arU!1fk--SulJFO#`sn(@Qa#lS z92O%fJ#TleH(bUGlvJBRT(}T77Wi{i<%oWhx1>{WJ7;4_MY}qwEW}5GU=hquDl035 zU}#j?bVeb_X1qzFdkA9t0Y$dJM~|)ceQ=}B#HIb@IJChLrDP98nF>qO^ndLX{rzcb z->1};&!~m@c+nP~F^Tp=N{o}jxLUHTf zT=O*jXU7K$yN}O!Pu%ux)J<@7eW}h}Vc|RHiO@9~zr_0@v!b!6BR4SurQ%ftJ$z-r(nSj zluB!RPy+BQ}vsxX597nu?Lmx t)pb0II@&I_UA{0b=h~*}ZrHz}!)m8JnhyBRx%~IBjx!%yVnEUu^M7U&Dfa*X literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/__pycache__/teachers.cpython-310.pyc b/sqlalchemy_fastapi_demo/api/__pycache__/teachers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b05e847670043662e22637484d012391d82aebd9 GIT binary patch literal 3085 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 CTQbrB literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/api/advisors.py b/sqlalchemy_fastapi_demo/api/advisors.py new file mode 100644 index 0000000..2c5effc --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/advisors.py @@ -0,0 +1,50 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +# 下面三行,坚决把前面的 sqlalchemy_fastapi_demo. 删掉! +from database import get_db +from scheme.advisors import AdvisorIn, AdvisorOut +from dao.advisor import service, crud + +router = APIRouter() +@router.get("/read",response_model=AdvisorOut) +def read_advisor(advisor_id:int|None=None,advisor_name:str|None=None,db:Session=Depends(get_db)): + r_advisor=crud.search_advisor(db=db,advisor_id=advisor_id,advisor_name=advisor_name) + if r_advisor is not None: + return r_advisor + raise HTTPException(status_code=404,detail="顾问老师不存在") +@router.get("/list",response_model=list[AdvisorOut]) +def list_advisor(advisor_name:str|None=None,db:Session=Depends(get_db)): + return crud.list_advisors(db=db,advisor_name=advisor_name) + # r_advisor=crud.list_advisors(db=db,advisor_name=advisor_name,phone=phone) + # if r_advisor: + # return r_advisor + # raise HTTPException(status_code=404,detail="顾问老师不存在") +@router.post("/create",response_model=AdvisorOut) +def create_advisor(advisor_in:AdvisorIn,db:Session=Depends(get_db)): + c_advisor,error=service.create_advisor(db=db,advisor_id=advisor_in.advisor_id,advisor_name=advisor_in.advisor_name) + if error == "DUPLICATE": + raise HTTPException(status_code=409, detail="该顾问ID已被占用") + if error is not None: + # 兜底:Service 新增了返回码但这里没接住,不要静默当成成功 + raise HTTPException(status_code=500, detail="未处理的业务结果: " + error) + return c_advisor + + +@router.put("/update",response_model=AdvisorOut) +def update_advisor(advisor_in:AdvisorIn,db:Session=Depends(get_db)): + u_advisor,error=service.update_advisor(db=db,advisor_id=advisor_in.advisor_id,advisor_in=advisor_in) + if error == "NOT_FOUND": + raise HTTPException(status_code=404,detail="更新失败:顾问不存在") + if error is not None: + raise HTTPException(status_code=500, detail="未处理的业务结果: " + error) + return u_advisor +@router.delete("/delete/{advisor_id}") +def delete_advisor(advisor_id:int,db:Session=Depends(get_db)): + d_advisor,error=service.delete_advisor(db=db,advisor_id=advisor_id) + if error == "NOT_FOUND": + raise HTTPException(status_code=404,detail="顾问老师不存在") + if error == "HAS_STUDENTS": + raise HTTPException(status_code=409, detail="顾问老师下还有学生") + if error is not None: + raise HTTPException(status_code=500, detail="未处理的业务结果: " + error) + return {"message":"删除成功","delete_id":d_advisor} \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/api/c_lass.py b/sqlalchemy_fastapi_demo/api/c_lass.py new file mode 100644 index 0000000..f505990 --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/c_lass.py @@ -0,0 +1,73 @@ +# # api/c_lass.py +# # 本文件定义班级的所有 API 路由(Controller 层) + +from fastapi import APIRouter, Depends, HTTPException, Query +# APIRouter=创建路由,Depends=依赖注入,HTTPException=错误响应,Query=查询参数校验 +from sqlalchemy.orm import Session # 会话类型 +from database import get_db # 导入会话生成器 +from dao.c_lass import create_c_lass, get_c_lass, get_all_c_lass, update_c_lass, delete_c_lass +# 把DAO层的5个函数都导入进来,接口里直接调用 +from scheme.c_lass import ClassCreate, ClassUpdate, ClassResponse +# 路由对象,具体前缀(/c_lass)在 main.py 统一注册 +router = APIRouter()# 创建本模块的路由对象,main.py会把它注册进应用 + + +# ---------- 1. 新增班级 POST ---------- +# 完整地址:POST /c_lass/add +@router.post("/add", response_model=ClassResponse, summary="新增班级") +# 装饰器:注册一个POST接口,路径/add;response_model=返回时按ClassResponse格式化 +def add_c_lass(class_data: ClassCreate, db: Session = Depends(get_db)): + # class_data: ClassCreate = FastAPI自动校验请求体并转成对象;db = FastAPI自动注入会话 + # 先查重:如果这个班级ID已经存在(包括逻辑删除的),进入if + if get_c_lass(db, class_data.class_id): + raise HTTPException(status_code=400, detail="该班级ID已存在,不能重复添加") + return create_c_lass(db, class_data)# 通过查重,调DAO层真正插入,返回结果 + + +# ---------- 2. 根据id查询单个班级 GET ---------- +# 完整地址:GET /c_lass/{class_id} +@router.get("/{class_id}", response_model=ClassResponse, summary="根据id查询班级") +# GET接口,路径里带班级编号,如 GET /c_lass/101 +def get_class_by_id(class_id: int, db: Session = Depends(get_db)): # 调DAO查询 + db_class = get_c_lass(db, class_id) + if not db_class: + raise HTTPException(status_code=404, detail="该班级不存在") # 查不到就返回404,带提示信息 + return db_class + + +# ---------- 3. 分页查询所有班级 GET ---------- +# 完整地址:GET /c_lass/?skip=0&limit=10 +@router.get("/", response_model=list[ClassResponse], summary="分页查询班级列表") +# GET根路径,如 GET /c_lass/?skip=0&limit=10;response_model是列表 +def get_class_list( + skip: int = Query(0, ge=0, description="跳过的记录数"), # 查询参数skip,默认0,必须≥0 + limit: int = Query(10, ge=1, le=200, description="每页最大记录数"), # 查询参数limit,默认10,范围1~200 + db: Session = Depends(get_db), +): + return get_all_c_lass(db, skip, limit) # 调DAO分页查询 + + +# ---------- 4. 修改班级 PUT ---------- +# 完整地址:PUT /c_lass/{class_id} +@router.put("/{class_id}/", response_model=ClassResponse, summary="修改班级信息") +def update_class(class_id: int, update_data: ClassUpdate, db: Session = Depends(get_db)): +# def update_class(class_id: int, start_time: date, db: Session = Depends(get_db)): + + if not get_c_lass(db, class_id): # 先确认要改的班级存在(存在且没删) + raise HTTPException(status_code=404, detail="要修改的班级不存在") + return update_c_lass(db, class_id, update_data) # 调DAO执行局部更新 + + +# ---------- 5. 删除班级 DELETE ---------- +# 完整地址:DELETE /c_lass/{class_id} +@router.delete("/{class_id}", summary="删除班级") +def delete_class(class_id: int, db: Session = Depends(get_db)): + if not delete_c_lass(db, class_id): + raise HTTPException(status_code=404, detail="该班级不存在") + # 删除失败(查不到)返回404 + return {"message": "删除成功"} + + + + +#API 层只做三件事—— 接请求、校验 / 查重、调 DAO,自己不写 SQL \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/api/employment_api.py b/sqlalchemy_fastapi_demo/api/employment_api.py new file mode 100644 index 0000000..3eed738 --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/employment_api.py @@ -0,0 +1,127 @@ +# api/employment_api.py +# 本文件定义学生就业信息相关的所有 API 路由(Controller 层) +from typing import List, Optional + +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session + +# 注意:下面的导入全部去掉了 sqlalchemy_fastapi_demo. 前缀! +from database import get_db +from dao.employment import EmploymentBaseDAO, EmploymentOfferDAO +from model.employment import EmploymentBase, EmploymentOffer +from scheme.employment import ( + EmploymentOfferUpdate, + EmploymentBaseUpdate, + EmploymentBaseCreate, + EmploymentOfferCreate, + EmploymentQuery, + EmploymentOfferQueryResponse, + EmploymentBaseQueryResponse +) + +router = APIRouter() + +#-----------多条件查询就业协议信息----------- +@router.get("/offer/search/",response_model=List[EmploymentOfferQueryResponse],summary="多条件查询就业协议信息") +def search_offer( + stu_id: Optional[int] = Query(None, description="学生学号"), + offer_id: Optional[int] = Query(None, description="offer编号,需同时提供学生编号"), + skip: int = Query(0, ge=0, description="跳过的记录条数"), + limit: int = Query(10, ge=1, le=200, description="返回最大记录数"), + db: Session = Depends(get_db) +): + #捕获异常 + try: + data_list = EmploymentOfferDAO.different_choice_query( + db=db, stu_id=stu_id, offer_id=offer_id, skip=skip, limit=limit + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + return data_list +#-----------多条件查询就业基础信息----------- +@router.get("/base/search/",response_model=List[EmploymentBaseQueryResponse],summary="多条件查询就业基础信息") +def search_base( + query: EmploymentQuery = Depends(), + skip: int = Query(0, ge=0, description="跳过的记录条数"), + limit: int = Query(10, ge=1, le=200, description="返回最大记录数"), + db: Session = Depends(get_db) +): + # 多条件筛选就业基础信息 + 分页 + if query.min_salary is not None and query.max_salary is not None and query.min_salary > query.max_salary: + raise HTTPException(status_code=400, detail="最低薪资不能大于最高薪资") + + data_list = EmploymentBaseDAO.different_choice_query( + db=db, + stu_id=query.stu_id, + company_name=query.company_name, + min_salary=query.min_salary, + max_salary=query.max_salary, + skip=skip, + limit=limit + ) + return data_list +#-----------添加就业基础信息----------- +@router.post("/base/add/",response_model=EmploymentBaseQueryResponse,summary="添加就业基础信息") +def add_base(obj: EmploymentBaseCreate, db: Session = Depends(get_db)): + items = EmploymentBaseDAO.get_by_stu_id(db, obj.stu_id) + if items: + raise HTTPException(status_code=400, detail="该学生的就业基础信息已存在,不可重复新增") + + new_obj = EmploymentBase( + stu_id=obj.stu_id, + employment_open_time=obj.employment_open_time, + job_time=obj.job_time, + company_name=obj.company_name, + salary=obj.salary, + is_deleted=0 + ) + res = EmploymentBaseDAO.create(db, new_obj) + return res +#-----------添加就业协议信息----------- +@router.post("/offer/add/",response_model=EmploymentOfferQueryResponse,summary="添加就业协议信息") +def add_offer(obj: EmploymentOfferCreate, db: Session = Depends(get_db)): + new_obj = EmploymentOffer( + stu_id=obj.stu_id, + offer_id=obj.offer_id, + offer_time=obj.offer_time, + is_deleted=0 + ) + res = EmploymentOfferDAO.create(db, new_obj) + return res +#-----------修改就业基础信息----------- +@router.put("/base/{stu_id}/",response_model=EmploymentBaseQueryResponse,summary="修改就业基础信息") +def update_base(stu_id: int, obj: EmploymentBaseUpdate, db: Session = Depends(get_db)): + update_data = obj.model_dump(exclude_unset=True) + try: + res = EmploymentBaseDAO.update(db, stu_id, update_data) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + if not res: + raise HTTPException(status_code=404, detail="未找到该学生就业基础信息") + return res +#-----------修改就业协议信息----------- +@router.put("/offer/{offer_id}", response_model=EmploymentOfferQueryResponse,summary="修改就业协议信息") +def update_offer(stu_id:int,offer_id: int, obj: EmploymentOfferUpdate, db: Session = Depends(get_db)): + # offer 表主键是 (stu_id, offer_id),定位记录需要两者 + try: + res = EmploymentOfferDAO.update(db, stu_id, offer_id, obj.offer_time) + except ValueError as e: + # 捕获校验异常,返回标准400错误给前端 + raise HTTPException(status_code=400, detail=str(e)) + if not res: + raise HTTPException(status_code=404, detail="未找到该就业协议记录") + return res +#-----------逻辑删除就业基础信息----------- +@router.delete("/base/{stu_id}/",summary="删除就业基础信息") +def delete_base(stu_id: int, db: Session = Depends(get_db)): + ok = EmploymentBaseDAO.delete(db, stu_id) + if not ok: + raise HTTPException(status_code=404, detail="记录不存在或已经删除") + return {"code": 200, "msg": "删除成功"} +#-----------逻辑删除就业协议信息----------- +@router.delete("/offer/{stu_id}/{offer_id}",summary="修改就业协议信息") +def delete_offer(stu_id: int, offer_id: int, db: Session = Depends(get_db)): + ok = EmploymentOfferDAO.delete(db, stu_id, offer_id) + if not ok: + raise HTTPException(status_code=404, detail="记录不存在或已经删除") + return {"code": 200, "msg": "删除成功"} diff --git a/sqlalchemy_fastapi_demo/api/statistics.py b/sqlalchemy_fastapi_demo/api/statistics.py new file mode 100644 index 0000000..998ffb6 --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/statistics.py @@ -0,0 +1,106 @@ +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session +from sqlalchemy import func + +# 注意下面这些导入,全都没有 sqlalchemy_fastapi_demo. 前缀! +from scheme.statistics import StudentAge, ClassCount, ScoreCount, ScoreAvg, Employment, EmploymentOff +from database import get_db +from model.students import Student +from model.Score import Score +from model.employment import EmploymentBase, EmploymentOffer +from model.c_lass import Classinfo +from dao.statistics import ( + students_age, class_statistics, score_above, score_fail, + avg_scores, top_salary, stu_every, class_avg +) + +router = APIRouter() +# app = FastAPI(title="统计接口") # 这行如果不需要可以注释掉 + +# -动态年龄范围查询**:支持用户输入年龄阈值及比较条件(如大于、小于、等于、区间等),动态查询符合条件的学员信息。 +@router.get("/students/age") +def api_students_age(op: str = Query(..., description=">, <, =, >=, <=, between"), + age_value: int = Query(None),age_min: int = Query(None), + age_max: int = Query(None),db: Session = Depends(get_db)): + try: + rows = students_age(db, op, age_value, age_min, age_max) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + return [{"stu_id": s.stu_id, + "stu_name": s.stu_name, + "age": s.age, + "gender": s.gender, + "class_id": s.class_id,} for s in rows] + +# 多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。 +@router.get("/classes/statistics") +def api_class_statistics(db: Session = Depends(get_db)): + return class_statistics(db) + + +# - 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。 +@router.get("/scores/above") +def api_score_above( + score_input: int = Query(..., ge=0, le=100), + db: Session = Depends(get_db)): + rows = score_above(db, score_input) + return [{"stu_id": i[0], "stu_name": i[1], "exam_order": i[2], "score": i[3]} for i in rows] + +# - 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。 +@router.get("/scores/fail") +def api_score_fail( + fail_times: int = Query(..., ge=1), + fail_score: int = Query(60, ge=0, le=100), + db: Session = Depends(get_db)): + rows = score_fail(db, fail_times, fail_score) + return [{"stu_name": i[0], "class_id": i[1], "exam_order": i[2], "score": i[3]} for i in rows] + +# 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序 +@router.get("/scores/avg") +def api_avg_scores(order: str = Query("desc", pattern="^(asc|desc)$"), + db: Session = Depends(get_db)): + a = avg_scores(db, order) + return [{"exam_id": i.exam_id, + "class_id": i.class_id, + "avg_score": round(float(i.avg_score), 2)} for i in a] + +#就业统计 +# - 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司。 +@router.get("/employment/top") +def api_top_salary(n: int = Query(5, ge=1), db: Session = Depends(get_db)): + return top_salary(db, n) + +# - 统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)。 +@router.get("/employment/every") +def api_stu_every(db: Session = Depends(get_db)): + return stu_every(db) + +# 每个班级的平均就业时长 +@router.get("/employment/class_avg") +def api_class_duration(db: Session = Depends(get_db)): + return class_avg(db) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sqlalchemy_fastapi_demo/api/students.py b/sqlalchemy_fastapi_demo/api/students.py new file mode 100644 index 0000000..26398c8 --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/students.py @@ -0,0 +1,108 @@ +# api/users.py +# 本文件定义学生相关的所有 API 路由(Controller 层) + +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session +from typing import List, Optional + +# 注意下面这三行,坚决把开头 的 sqlalchemy_fastapi_demo. 删掉! +from database import get_db +from dao.students_dao import StudentDAO +from scheme.students import StudentCreate, StudentUpdate, StudentResponse +router = APIRouter(prefix="/students",tags=["学生信息管理模块"]) + +# 增加学生信息接口 +@router.post("/",response_model=StudentResponse) +def create_student_api( + student_in: StudentCreate, + db: Session = Depends(get_db) +): + # 1. 校验外键:班级和顾问是否存在(与更新逻辑保持一致) + if student_in.advisor_id is not None: + advisor_exists = StudentDAO.inspect_advisor_id_unq(db, student_in.advisor_id) + if not advisor_exists: + raise HTTPException(status_code=400, detail="该顾问不存在") + + if student_in.class_id is not None: + class_exists = StudentDAO.inspect_class_id_unq(db, student_in.class_id) + if not class_exists: + raise HTTPException(status_code=400, detail="该班级不存在") + + # 2. 校验通过后,直接调用 DAO 新增学生 + student = StudentDAO.create_student(db=db, obj_in=student_in) + return student + +# 查询所有学生接口 +@router.get("/all", response_model=List[StudentResponse]) +async def get_all_api( + skip: int = Query(0, ge=0, description="跳过的记录数"), + limit: int = Query(100, ge=1, le=200, description="返回的最大记录数"), + db: Session = Depends(get_db) # 依赖注入获得数据库会话 +): + students = StudentDAO.get_students_all(db, skip=skip, limit=limit) + return students # FastAPI 自动根据 response_model 转换为 JSON + +# 多条件查询接口 +@router.get("/search",response_model=List[StudentResponse]) +async def get_multi_condition_api( + stu_id: Optional[int] = Query(None, description="学生编号"), + stu_name: Optional[str] = Query(None, description="学生姓名(支持模糊查询)"), + class_id: Optional[int] = Query(None, description="班级编号"), + skip: int = 0, + limit: int = 100, + db: Session = Depends(get_db) +): + student = StudentDAO.query_multi_condition( + db = db, + stu_id = stu_id, + stu_name = stu_name, + class_id = class_id, + skip = skip, + limit = limit ) + return student + +# # 根据id查询单个学生接口 +# @router.get("/{stu_id}", response_model=StudentResponse) +# async def get_student_by_id_api( +# stu_id: int, +# db: Session = Depends(get_db) +# ): +# student = StudentDAO.get_student_by_id(db=db, stu_id=stu_id) +# if not student: +# raise HTTPException(status_code=404, detail="用户不存在") +# return student + +# 更改学生信息接口 +@router.put("/{stu_id}",response_model=StudentResponse) +async def update_student_api( + stu_id: int, + stu_update: StudentUpdate, + db: Session = Depends(get_db) +): + """更新学生信息,支持部分字段更新""" + # 检查学生是否存在 + existing = StudentDAO.get_student_by_id(db, stu_id) + if not existing: + raise HTTPException(status_code=404, detail="学生不存在") + # 校验外键(班级和顾问是否存在) + if stu_update.advisor_id is not None: + advisor_exists = StudentDAO.inspect_advisor_id_unq(db, stu_update.advisor_id) + if not advisor_exists: + raise HTTPException(status_code=400, detail="该顾问不存在") + if stu_update.class_id is not None: + class_exists = StudentDAO.inspect_class_id_unq(db, stu_update.class_id) + if not class_exists: + raise HTTPException(status_code=400, detail="该班级不存在") + # 直接调用 DAO 更新,学号不可改等逻辑已在 DAO 层处理 + student = StudentDAO.update_student(db = db , stu_id = stu_id , obj = stu_update) + return student + +# 逻辑删除接口:不返回完整学生实体,返回简单提示 +@router.delete("/{stu_id}",status_code=204) +async def delete_student_api( + stu_id: int, + db: Session = Depends(get_db) +): + StudentDAO.delete_student(db, stu_id) + # 返回 None 表示 204 状态码(无内容) + return None diff --git a/sqlalchemy_fastapi_demo/api/teachers.py b/sqlalchemy_fastapi_demo/api/teachers.py new file mode 100644 index 0000000..f02b9d7 --- /dev/null +++ b/sqlalchemy_fastapi_demo/api/teachers.py @@ -0,0 +1,81 @@ +from typing import List +from fastapi import APIRouter, Depends, Query, HTTPException +from sqlalchemy.orm import Session + +# 坚决把下面这三行开头的 sqlalchemy_fastapi_demo. 全删掉! +from scheme.teachers import TeacherAdd, TeacherResponse, TeacherUpdate +from database import get_db +from dao.teachers_dao import TeacherDAO +router=APIRouter() +# ---------- 创建新教师 ---------- +@router.post("/teacher/add",response_model=TeacherResponse) +async def add_teacher(teacher:TeacherAdd,db:Session=Depends(get_db)): + existing_foreign_key=TeacherDAO.inspect_class_id_unq(db,teacher.class_id) + if existing_foreign_key:# 外键校验 + existing_teacher_id=TeacherDAO.inspect_teacher_id_unq(db,teacher.teacher_id) + if existing_teacher_id:# 主键校验 + raise HTTPException(status_code=409, detail="主键教师ID已被占用,包括软删除") # 资源冲突 + return TeacherDAO.add_teacher(db,teacher) + else: + raise HTTPException(status_code=404, detail="班级ID不存在,数据库无数据,或已被软删除") # 关联资源不存在 +# ---------- 软删除教师 ---------- +@router.delete("/teacher/delete", status_code=204) +async def light_delete_teacher(teacher_id:int=Query(...,ge=1,description='输入想要删除的教师ID'), + db:Session=Depends(get_db)): + """ + 删除用户,成功返回 204 No Content + """ + success = TeacherDAO.delete_light(db, teacher_id) + if not success: # 目标删除教师ID不存在(被硬删除或软删除) + raise HTTPException(status_code=404, detail="教师ID不存在") # 关联资源不存在 + # 返回 None 表示目标教师ID已删除 + return None +# ---------- 更新教师信息 ---------- +@router.put("/teacher/update",response_model=TeacherResponse) +async def update_teacher( + teacher_data: TeacherUpdate, + teacher_id:int=Query(...,ge=1,description='输入教师想要更新的教师ID'), + db: Session = Depends(get_db) +): + """ + 更新用户信息(只更新传入的字段,也就是非None) + """ + # 检查教师ID是否存在 + existing_teacher_id = TeacherDAO.inspect_teacher_id_unq(db,teacher_id) + if (not existing_teacher_id) or (existing_teacher_id.is_deleted==1): + raise HTTPException(status_code=404, detail="教师ID不存在,已被硬删除或软删除") # 关联资源不存在 + # 更新班级ID + if teacher_data.class_id is not None: + # 校验外键,校验班级ID是否在Class表存在 + existing_foreign_key=TeacherDAO.inspect_class_id_unq(db,teacher_data.class_id) + if not existing_foreign_key: + raise HTTPException(status_code=404, detail="班级ID不存在,已被硬删除或软删除") # 关联资源不存在 + updated = TeacherDAO.update(db, teacher_id, teacher_data) + return updated + updated = TeacherDAO.update(db, teacher_id, teacher_data) + return updated +# ---------- 查询所有教师(分页) ---------- +@router.get("/teacher/total_query",response_model=List[TeacherResponse]) +async def get_teachers( + skip: int = Query(0, ge=0, description="跳过的记录数"), + limit: int = Query(100, ge=1, le=200, description="返回的最大记录数"), + db: Session = Depends(get_db) # 依赖注入获得数据库会话 +): + """ + 获取用户列表,支持分页,从skip+1条开始返回 + """ + users = TeacherDAO.get_all(db, skip=skip, limit=limit) + return users # FastAPI 自动根据 response_model 转换为 JSON +# ---------- 根据 ID 查询单个教师 ---------- +@router.get("/teacher/single_query", response_model=TeacherResponse) +async def get_teacher( + teacher_id: int, + db: Session = Depends(get_db) +): + """ + 根据用户 ID 获取详细信息,不显示软删除 + """ + teacher = TeacherDAO.inspect_teacher_id_unq(db, teacher_id) + if (not teacher) or teacher.is_deleted==1: + raise HTTPException(status_code=404, detail="教师ID不存在") # 关联资源不存在 + return teacher \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/dao/Score.py b/sqlalchemy_fastapi_demo/dao/Score.py new file mode 100644 index 0000000..d279d41 --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/Score.py @@ -0,0 +1,56 @@ +from model.Score import Score +from model.students import Student +from sqlalchemy.orm import Session +from scheme.Score import ScoreCreate,ScoreUpdate + +class ScoreDAO: + """用户数据访问对象,所有方法均为静态方法,方便调用""" + + @staticmethod + def inspect_stu_id_unq(db:Session,stu_id:int): + return db.query(Student).filter(Student.stu_id == stu_id,Student.is_deleted==0).first() + + + # 查所有数据 + @staticmethod + def get_all(db:Session,skip:int=0,limit:int=100): + return db.query(Score).offset(skip).limit(limit).all() + + # 查询单个数据 + @staticmethod + def get_by_id(db:Session,stu_id:int,exam_id:int): + return db.query(Score).filter(Score.stu_id == stu_id,Score.exam_id==exam_id).first() + + # 添加数据 + @staticmethod + def post_score(db:Session,score_create:ScoreCreate): + # 将 Pydantic 模型转为字典,并解包构建 SQLAlchemy 模型实例 + db_score=Score(**score_create.model_dump()) + db.add(db_score) #添加到会话 + db.commit() #提交事务,此时会执行 INSERT,并自动填充自增字段 + db.refresh(db_score) #刷新对象,获取数据库生成的默认值(如 created_at) + return db_score + + # 更改数据 + @staticmethod + def put_score(db:Session,score_id:int,exam_id:int,score_update:ScoreUpdate): + db_score=ScoreDAO.get_by_id(db,score_id,exam_id) + if not db_score: + return None + # 只更新客户端显式传入的字段(exclude_unset=True 排除未设置的字段) + put_score_data = score_update.model_dump(exclude_unset=True) + for k,v in put_score_data.items(): + setattr(db_score,k,v) # 动态设置属性 + db.commit() + db.refresh(db_score) + return db_score + + # 删除 + @staticmethod + def delete_score(db:Session,score_id:int,exam_id:int): + db_score=ScoreDAO.get_by_id(db,score_id,exam_id) + if not db_score: + return False + db.delete(db_score) + db.commit() + return True diff --git a/sqlalchemy_fastapi_demo/dao/__init__.py b/sqlalchemy_fastapi_demo/dao/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ffff66e5e85b30dca145d1877153575ea4f533f GIT binary patch literal 2291 zcma)7&2Jnv6d!v&ceA@m(+1Ksf|4Sn0Tc-?NC=^#RE1NhloX`ZqS0pUC6mnTZ0uQR zqKQGV%qD4qlN+b@1Lnz_^L5QCCCw!${niB_ZoOsW(AKCCBEcwl|-?ROGKR>@o z%H^T~?OA7k?HA85e#OD@X2Reiba@#BGZ=}Cm{bWtoklb^tESe?$cpW%t#vDMVz=tX zUezPU>jtx#bHiZH4y_iLyJYy@5$t97MA=J?L~u~trL@C%E7dBOGE7=NRb$$`Ab36H zy}{KsgFyq=A8!R1T!b#a2EmOgVMdiQQZ>27D7Tr(ouo-T)|4(Qf3vss?f8H^CIju!A|MfvEJ+?>;(SoG%qzhc7{!9YkAZP=RC$9 z*Om&K1}0{dr!ii7?aj^`5c+SQe%1Zx`|j;~-CGBb4(=a)cJT0U7C_LGb8KxwHSQ&=&rqIK#+7%5b*RJWp8x2*c6x(%4vpC%7sAc zRWXzS;}K6eQ+6{HGWDr|bTYJg-w+kh|6E>pxpq}@A!~1kEtb45YgaZKt921y5y={F zq&QAjlU8r|QcZ3|^{BDR!e=+ps#w;Rc=72FCOU zLY<>q=lTTC|J_gHI%43cEV&-Gl^um~m^Kh#zoCwO0lJ(4F=Q-5-pq`Gw2-NNvgq3a z-;=<@m6J4^lBePf4$OKK`DRYaX>`F^%}XxE(aC+6rvW(PK;j-VbZcS&pl4JrzgCa& zW>3cXKW;Xo!z1=wkeQKk!XVSn|p@-TD=*XCn?4S z{A=oqaRT`muuj|t<{48?BZ=W^l`D8taJkxtbq*FOkF5kcx|8=&Y$p;D3j;?&B;M_$ zStK4Q5{qn|9>5&>DKEzvvOeNYUb8G%+i&9C`;zfau|~I@Z8rt4%*osxsJ|OizzRH8&5Dy*nkNfbF&CGiq?Y-$Mg;X0 zo(80&?+O=A6qw6m7KF0Hl*dxJV63O95Ko}xNf5r5=j$9!=#034+IbMwO1slzCV-M$ zS7cq0_fGOx7&zfVISHadEugMMCrG7F<1kwW?jxy<%njIj9tI<9nVAV}5nu~*#5|rO z3^T)Ayu9pNL(Iy_E0u-`23@9x2+za*Ct;NG6?r1O01mPQB1eMB0I4uFNQL9Ri%xIw^@22Ml8OT$LYp(ZkcBq%d%rD6g% zoJOIq5SbBAp>R<6D4s(xe5YE&nxa`iH;EVT85W`R459W6q1H5X&6fT=a|T z!oL*ZdHurXHSGM&J@en5P@eG@FZ16=W#~Mgh&YG$^l);d;Ll6^3Gm)w8nDKy^Y|ZN XD({t?+*gr&{c1}_iIm6$nWTRK;o~w~ literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/Score.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d69e92d437851113cbacae56cbb024bd606dfbb GIT binary patch literal 3555 zcmbtXU2GiH6~6PkU8`yF17KGQm5~rQN*WA(AVG+qK2_>VR-1Ois1cExY?Hp!#GpR(rRUt4 z{WHdG#g%;Sx#xWM&dmAFIeY!5&dxA_(NA9=`%oj~Z@8!pIZ!sf2g(wmgbEhP2nj(z zU9`lEl#sYCS#m~6C|s8~Cro)i7k5^d9=n06Z%F~L(t%&g5o z35~dU$|hW{GRH}0Ct{-4&fQ0CmULOLIGLlcF#W@P*%mA|{s77nVI(0?k`SqokeEzG zrcjBgDVfUi^0@$-2!SWUeF{^l3VxM_=9Ri%YwV;N_qH|dZVS9&7KU@%n>_7-rvpxf zeYBHxq%_*qgy?KVz;pE`Z`bsWShuI~?>=_q`}q^_!he5ZwOV|;`r=ykR~K$wc>ng& zg`00&y7lHO|9tm!bz!c0W}*7hrRwiry!rAkZd`ol_RGJi&i&lCAmF7-H{N^y*4lG$ zh$qrfPj%e9k)~!q2ag95Ey3SL5yTQHkTHSVTZCKRaW3$VDJ=lLXrRW_&wC5P_+CQl z`)kBC0c!+|kh8*YO!1V-JhP{5d_zx7r7f4)b~`SVRN8jjm}q1Ea+8BE*w^>jQ!vF( zI?Q(BX_NglJrO^~oN+gsi&x)zuKL@ho4Ac;ogHJQ8+RtHq-CCB znQ0?%8I)zRahlA=IUPf}X|Fpy;p6~q_)#?S6O%K$YGe(4-icr641t&<*Y(KrQwvjP zLS?+9>YBM1pS%UlCsGdt?h3@kcg;~*L#RDSuhiat=%2UciV|3*dMSJL;b4V3kV zD*AzvexR%$x~v_tqj+wZO(io%)~3vE2_dE~58-)GzFY|Zmy~b9K$qP-3L-Cypuom3 zzc-CWS@@w=8=gHM=50h`zs30*sd`?pBxmJ`Gg5)+5d zVq)V9dErc!GRvU(Ob$|-QcpFr8K_M!WV4jboKv;1e+AJR9W{6WT4Nv1WgTcA7@3)9 zJ@^e{FYI+51u;iHRY~{GQslwq-Id-4O1%%1d-ubts9n{<&#Mb+aq5b8H|lK*ZKvB& z2`_{fAG)ILzN+sm>OKdW&q11c0ULS$_fv)^)JC0+e}DzpsM*O@JQRQ*h*H4NtXz;C zVVV@At@xnA`FaDHRSL>>j2t6B?k40%Py@5-Y{;#1Q;-X4Ayj*wKu-6_$Sr2}rqRMJ zHl$6XAlI51urC9*((sdT-RNXfrUiEo=;hF`Vj&wJZSO|W2f|a*F3UJx2%JgRwe7E= zryoR2^E=ueH1N_JMD0EhURN$3kZizpCFu#{p70X~OCLHOAAZ|wtK*s~v2MesI2MRG zawF1PiS(Bu{VU&DnOX~%BaaldkMx~aqdTwn4*2PD(Y=g0a;(^OHF|F)I#`Mh{v{e) zI9fbXO#Zbax_Dyw2g{Rx?znedB0XQfzJ1+kMg1$hFb~t^4k!Q138|$$ZiZJR!rNSrg50 zD{<3ihPkJ*)W#;~N$CmKhT<0@o8aFuq z1~E@Ql7DzziL8r)^0=`4>^i}Db>t48HzcBV`>ypcsGk7p@Zz@-ba+ML)9O)#9g`k0w=bmSs?l`h(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o11}*(xTqIJKxa zCOk7QCBM8lCZIAoBe5tqpeR2pHMs=DFUiQygK{lmiVJfRbCNSsb1UQ15{pX`3o_$V pQgicTQWEoH;^Q;(GE3s)^$IF)aoFVMrDpyab}rCQODrx)EXdR?D9X=DO)k+dF3d^HNzO>k zt&E3C#iyj^=If^<=Ih7DXXa&=#K-FuRNmsS$<0qG%}KQ@Vg*{n2*kx8#z$sGM#ds$ GAPWFF3N_gP literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/c_lass.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/c_lass.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e12ff5679bf06426a266b938577d7e385d0147b GIT binary patch literal 1703 zcmZ`(O>ZMb5S{Lx8ILEn<79WkCP;u*%ZE8c+*U#eAq8e3&O}(eCwq&XjCH8}1EVpC>Ck^?~pS5td?a%A}Jdtg=^D^o-Z{OTiG2Xf-@8hl3 ztv6NM@IH`x@V4b!CqZZb8kq+j=4vO(n7kTeTR$o??8n2Z!`+rQjp*YA{NwcK)8463+VsB5$Flm#^q$TJ=b0{_>T0A0mTY@ojo0Rrp1CZt zVsNg?S$~)zl}X;0s;qi4t9pYzC3!fRx#qw#)?axV_>-X|+brb?OIgVD4osi8i?y;- zJ>FoA7>qDHYmcx2H-TkKw&0eH#GGBw8cM87zKE8=N${E2qb*2=-tbfE7<~_+otnOnWmV$`w4*d!Tn&dt zS^YK{A}flU`W{dSc~=-b8V{sJKoGbF^DaURDI(zw)&>~;4h)x0y|76g8xU$ZysgF8 zFrZ*)_yxa$ZbwWq$zQRna2_uBGWat1KJD?V=qk2iF6PlZet|pSa(hGD!mC|C+v4~c zIdR>fW^=1b<7zn0tkt@S0F5h&IP%)|^&?;|fxvyU zxUDrHv}@+Xg_^nO$E<)f{#EDZI&LM_5AhL0pH6v0v_%W$_JaKgt__V+X=xl`n8%oI zdEs+z>XMz{7M$}w19mWjn~o5N$6sBOOrN1@1k=~lYpuv{*p)s@#iC_|xpd8oRxn?hWxpa1~ z?ZE~v7&HaJJP65?Mv&T)7K%^plYf9OJuZ52saQ}8eLIPL_xqjO%_TL>gAVL`zw`Zm zXLjcE{my58jK^aH+W6Pkb64Vo{EmaLMFM5>Q&5(PNla>!Je{Nzb;*|U@}w+u*;exE zq?*?zH5e<5nkrMXim5FqlMykFuqce9Fm5sT2}=u$nlZ3yroNy~#=Qi}gZhy%<~UYi2Go`_b{h1VY{8IxT@21}mUdY%n3y$jAek3@xo{zu zk%DufP~el{+q?zcGI1#g(L9>l9@n(ujHlWyx)#LFNgm0CxNVE_q_tpWN+6N#z8E4dU~FG2r@b0FzzI+47*~@BnO!@?G|Q}kG}up(O1iV z-oF0Fz13tk4ZoeWUZ3TK9Lu;#=aQYaGgB;IN(HWz$?}DynJy$VDco!SY{`#jM0!#U z3*Qg_8ida|0bQ9qhq^&#zP~)O3DX;=-aW;O;9f@fw~~w#8qM8Gc9^J~8v2^D8I{wT)==~4^ecpH z&EF%*W8@|sHB?`{RAjs)vgK=8%XS$TS@YGb#U0m>8X3YwI=I1}9=;ERAG^rh5WRz7 z7{P!ypevINJ^sbOwSh0sRrT(g-doXozqM*d2P#Jg?w+k29jxl_*7V_uK3vsD?kgia zfy*h*v^DFiwgu&p!3qc)>f&}Rfb##K^XL{Zd)|+|?#3A5ov;x@<c?vO@rr)@PH$BosOcvw`pK$( z>b`QS0bi^r2nO%Z4)m}@1bXYB?BEsxXoQR*d$L1I#FKK{k%t-BOnPgJIp!2k*{vu; z<`^U&LpDExb?4MM&D}!TlReeb)`Hb3`Mgv4uN)+YIRuuHfrI4Hap2!LyPC0!CQB7( zAQQkoSdxA$Uoe@SGK+aAEz4zj$B%$J?Yf-9OG9`YbVj6E;rs=h76l>_q~_}ZtU%sr zU!G5j02bxT*w+jg1MdDc2kMYz-+;3|> z2mJ+}=lEy;<)(4R8__T7r9a4_f}y?73U%;_VPPy1HOI>)UJ_rnW?X>-$Ggq38aN*3 zCJ~!#luYy_{H|!TQ~XVE;e+7JLsyq6rB6Ic=#gK^JHL_h^{7e{OBd?|#Om-Sih6?5 zQM&YYouFLJYzp~TjMCFfSI~HRH6z3w;W}N9#b_rk0pdo75Ob%7 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2909daf09da89f17b9b6a665a7dff7d7da0a463f GIT binary patch literal 4525 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 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/employment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f92ffd7c52fd276fbb3cdca623b245bafde789e9 GIT binary patch literal 7213 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 ShhTd*>pbG<-yqOXYyKAsd|6Wf literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/statistics.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/statistics.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16396bf2451ff1459346c73e25962d951741ddea GIT binary patch literal 4637 zcmaJ^-ESOM6`yn-AA*qSB$kw4_jI9TPPT0xFpZ(^M>uR^z?1&aP*7 zHg{&zI2ua@2f;%T1y$mKNbFW>MV|TqQY8@d|Cm>rwthnhp<*>LzjJ53AFj!+?wNb< zId|sF`JJx`$HyHFzx1DX>nle!?H{xl{^hZ_fDye1A~eAQt-(sH!AqRcng@ErC>d(5 z2WG=6S!!+sxrSY`8~IXRtT9*82w#s@FKlHuHhatGSEK8J7gVnKjm>h^ zi(;=;gDQ=1Re0elmT@hLYn5oBwV4*8%wMB2RLtRF(OHmVrp=1Xp0xi3I&S|Pbj(sAC}K>B{2fF9)2=Ti9O3LNr)C_+KuCwepS=CS4!x1`Ckkahi2QPDG`zr90{7ni z6M*(hl> znCUw30@603+s?9icAQy^-=8)3=LTG0ju}i+%v4D4{U40uW{DL()#i=xPAq z3;@vUraTuLztE~kL_)u9)6UD3pX3Oq^i zC7&X48YH#J3z}X7iQd2IHQ*4gnc?^>u`TIG?I4DC#BKRiIz<^lK0`#|*;8C;@-%j% z2@nI&%`u0aWc&?4_&m0D7C|axrTrg8`#~J_!^%e=$6@?{4B@wB##Ul(!_pf-IKdup z1csd)u*)#C>P}*f;HU$K|A!-)n0#L0xK23c`#2(g680N@9RZt}fnHdC1q28>Rj(G5 z6)r;nI*Swtm9WuT`Uc&VT;+HlKRPl5UtiQ6dpLfn9{9}+MDjTm+o_}Q3nfC=%_#_b zI>ohyAITR;@asfKk&;Qzj)oxp7O@nhPUc)Bpgfw21tB`a3dp)WOuvoI)DV7D83|4@ z9|h<|jHnJ0YaJHzx{kbPP|ihG)H)`1tT+dNcvtV_v2ws4!%l%RG3C&Gi7uz`MgGh> zgtG|I$*$ILCCr`j#8(Jq%R-yZ{Z51y$P9!IPw076NBzrqbhcG$X|` zI~w(nx}9EO8e~EFC5WW9GBBmW3$)a|sG{P^&9Yx=D!zP)Zbz9g^92<&nQ{9XM(4p+ z;WCY4N5zW;uGtBZ-)L=-C0%f2; zp$$`oirO)bLIqhWQ!q3cme0~`Qjp7Di6! zcg#UF$x~3yHB*BUN@h*F9X92;Qhl3J_t#YQ-cW|R<4#Yam zn9;i;fvG-P?~GArp$Zr}W=ekp(~syvUQW8KU_@U7QHkv6sa&!k|KLY}F6L_o66D38X-V=eUb)1C0mn;fDtbj4*$d|~B2vnRJhunBCa5?hg zU_AlOBz2#V%C5Y>HakUuu!hG?(R1*GX$oy&3hOq)x92^%Wrb*JQ(7X3%wbNzGc+3}aOWvXq}C6=lFf(@MUt<{Iu4Jqbcth3}!s-Lv_GO8G^- zh)&7I-$CnJ(D`Q*dASNvS6^OUM#O!S=1gTc_gLx-zOB?-W-a@ZgWZuYu7yU3Z@`6K zEsL@*#M2KKUZLJp70UFfhf5AZFte+QzB3O$Qz_H8ilhjUmqAj!){NCRoa*#duPCXx zP-Rf1Sruc-Btw4D&n>CFh?i^!{t{Ju_4!!T3NUSv%&T+8nSCF0k8}Qj>&|_9)-E`< LA4BJVF( literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf1b1574775654b6f7dccc48d5b28aae16884898 GIT binary patch literal 3938 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 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/students_dao.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae9aaef780ad85e86059d893f812ee103ac9f1fa GIT binary patch literal 5460 zcmdTITWk~AbsnDa*dAx>gb-XpNPv(`cAFHcg;k(kDBFcrn}8G$t&8v)&jcpeNthWI zg3K1W+sZD`fW$6AWt-5lT_e~MAys76YQL(gQhzcslG70tsk+IMKSPA}x98rOv17|& z`6wT~iSIr4o^$T&Jn#I&@Anc=Hb|cgZ1xkxe^AFME*n@p1i)27A|x_SB*-vHBAAL( z2|7$;n2x&=Oqjv2E6yg|VRwQHbGXmMJqd5voA8BwBta3o35k85kleQ^YxXcd!ik;* z)DcP3-6w0BGBgOFf6xB?`@VlFCJ*b@fV)pmO7fsCQl{Sqcd2qzmy6v4!xD4>&+Wxb z(YWb)Tha8GwUkxY*qy~$0Im`;5hf)fOv$uF$}WkLnSPfK#R;ejrVSQlLC}0eXD*C#J{_C8 zp1nnxK24A6Ni7l^l4O&WWId|HZxJGIGAELt zSAP@^F|2%ZSRERWV|tf%A|8#$j>(CUh>e0hCWgAC=uj8z9Qg~_b#$n6c*LxUVRsR+ z$4`g)ECR5M&Tn^p5q9C$1$7{uSuw z`9_0poM1l@ZU_e7g-4nUzG0d6~_|yFO$B*y+ZtfS^h4-?S)?;fB-72y^tk&uZ1R+xb z|JUEI$-258b?9h3F4C5Iu0tefR6|z6w0s7Ocm*`C;60vAMfa)w! zV2MEO=&8)9>+YP;oEO>*q3w=4-`;JscTYu)_BV3Ej=Zqj5O)9Fl@ogMLZ2b@P4EA4 zP6+3P!-jA;C%iMwy`#3kY%1~+WiA^TD;DV;0A9XGm$>yRjyPqxSvx>f6RhLXu;`j# z%kvYT&0qYZC9W_3^5NX*{ke-D%zt#l5~d|UwweI(Rj5e%B4r5<-HnFUc0?9jB9+LI z5pZLt8>`FA!frql?11V8g!WKaIr?tq-HDYT%|)6Fh>yh1TlKda3N-22gk{yMu7s&f zE*6h!8mt{#8VB8g!eaXy*vQKln`2F9Scq=qxpgV_Yhw2D!nJMs44b0PZT{MMs>I@I z(O05U)Nde{{HPccOFK@{FR))Hn}ch0N{YrYzqDVrTBJ_7oRzA^XvV?9dD-X1Xi#X{ zioPb?uSA{o~ei0Xrqf>Pzv%}aE>Dg|0!yAKuUdoAG?M)zd)TsfHI*W~#P2EXCv!F=mh zqjl@lCZlzGj{i=YoZ&Xk`hwHGH8X*r6%EImt~F)17@>$6^F3upiQ z`18w_%Fd@R&HZW|zE{u*?Wjp9lIVF6^)2bEow;It#j0ACxz<>(wW^w0j@k#i(@sJK z@15srYM>z>SZ4&*O+<|VN`Gog=}$FHoo!r`W*=~&>MGap%H$S9=$_`fvEo5GhrH#2 z1eM72_SzS@4Rr%17s0R4NW}C;BJko&#$|x{NaRE^8b|L_)I$$kC61Fk9NrYRc@@1>aD|+-wh@H+J~7J# z3zVN(IkvSxK$Goxikd~5U~BPsp$VWT6vafzv4aHywb@-(JGJX6?%Tu&Rp2lm&1@Pw zS|FgwYEMyPlK=#7Mwpo;TE&@-9q4~m2#orPzm92`2|)S@?d*!ivA)Ya1qNWCY*;&{ zT}~9-sK+@y59)b|x|IbVf_P#@!&5Yey$~AfaE{;{Z9P8WWYrTEC=as@5kixNb3ucr zdVblCa6@Bg4wzQ7nBG#Vkv-<>EHE?UsUlSKSRH$aFQ7h(U@^lFz&Zx&B{7%N)`D Vh}idtX!(lmA<1n|2~^|r{ue*tO1l66 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e9f9e3ca4288a4210a4975dd96a5c1a14ac7ccf GIT binary patch literal 3176 zcmbVO-ESP#6`wm_yI!vy#{>r`YPXaIR+TK^rNSx*lqd+PN+Ttx($>{zviB~YWMkz#lNL^~|oH^3D_I+?m;32e%K*>fXKg z+;hKv=bYcUm4Shb1mE`~YbTeplJsBf^nMC-UV`EthKfp**pfpEgkW2?Wk)F}j#^Mf zU$HeuFX*DJ+9@YpNE7K5iE30oD^dN7TDMO>u!OGD=+DDG9Lm{cHCD#%QsgsD_!T1lk} zRnMwtNI{RK8cTsxrzs&#$I`Tr_R)-x_U+K^r&%G*bfvI%e@UkUbWn_BVPr(?xtFEr zFs!B1hv>eu8tgkjABOAi?_BoK%YX7^dcx0o(d7-euUVAg_{oRxYfuhCai4?A0~1(M zjWkG8S|N*MMy^Q>xh6NkB+yctlK59+i46P6M?RDC8pmb)j8mb^HfYtE^c54Z){7O# zu{=M;S&1`uBCl}7k@pF0dcug0#?ehg^}}Bdj*Y+OGVYH5*(%e@-`w$|)5QssJ4bot zBrAH@_a-XkxcmEYcgi+xFs?IgluXw%CoO|Ar!r2>%6PoI3sH2TPZuUaD5#)Vlj_c;i|ye=fNAdHbW!+uyDS^~Uy$vWpd zd*(G?o2oKC9hplnS+>VGABJ=JTFK(BmzN_0p{Q#VK7<-0R@t2d3nTy<7B#BnDI9YV zh{v?kzwW_rcWpmi#1MnIKLN7iiBG^{KLrv1RVe~0H#7mLT)hN}oy$dlww7+THdYfr zqh10;3}~=&835fC$8hl-z^)g^WbS;h@YU9x1pqp{@P!2q#cbv=`ogoj0?i4WEU)v2 z;E(HA?Zaw6RDPyAn?DSK1acgF5b}KqhzV#2_y{Npz@N}g|7sV&dv$k!jN#t#)@PvO zNexniaBs>G=rSLu$tPumnD3zw+LY8}0|`KcJypPm)#^Ez)`2{7wa9Bb!ZFUgDld=a zj`J$ZwVP|Lm5o@jelhsRhv2%0P1{X|k_bR>Z@wQ~TZ8f7_P={=5Y{iZnqNd~bhg<> zhz}pnt2_k_j-c>Iuo{3W;Thq^dr;aTn8=s2k^KzYdVRus928tgPf}JN1QyVN4S);w z_dwgLT|^j@5BKi)?H{275CU*iULZ4y2Q(1FtJV~R@sRY_%(y(G&FG$5Q)^mHKcf(7 zY6w6EpBCJz*Hpo_D!{E&fp@!bhadbWy!<7wLRi1Ob*~xDtpiB}OaF}ITbqsG+$Z3U z+t+WjKHCUxz8Bv5`u=7&`o|_sZaO)7Vk{S4`Vz<|*m!qq^J;tjdI!{4C1E>E7-PAZ zTt1zP_K6mTeR4;qsaf`{VlG^31~)ErS4lh|o^WvywUN|w-EjK!@4#E}T@up=^(*ar z%fSaXaz`p<)>-d3Waa_(X3?%v1_9tQFQ4N50Cv~(zGivMas3nwnx4mn7w|#Q0acN5 zge!==(_a;tU!+5h&fzPk*tD;`VcNir4>*b*Dd$1W#pSYnSu#WhlZ3Ii$4Meh5&GK{ zmsQIW#m3V z{XL+Sj#@;vsfcVb7$dSpGVt|EsRS;;e~TT(wC#i$o&!Di@p%{%EPJ5u z^l*=rPg_7NiQ z`6Us0NAekeu=`vZt#C)2!hfnO-0_AQb@5%rMq@s3qvPVK3J3nz6!8S?&Om$kPyT=9 hqJd9>C{GG9-{qoy`VSGRFCyyV-IkSyNEUv>@{bUz2bBN- literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/__pycache__/teachers_dao.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..917e5155ca86179ec18259641a0ad60a67e22813 GIT binary patch literal 4139 zcmdT{Yfu~46~3!|NQlSA$Pim;$hK)}3lA_;JIO@jal@E8ji<4j#Qwvy)yUe#7S;pr zt{TJ0GtiPowAg5-PKXmsVCooB>_F3YEK_FO|NUc)+{)car}CbO$^exD%i>_v@0P zM3aetOY@$P!jUtQ+%1Y)qt!k+Acj>5+gSt9tUDYF!<SwnZKsW7LuvVfFShydyuva1ax`*{uE4W@q z0oSpQP=J;3fi-VDDN3=Bn2HZ*bQns%mao>XRkqOn{cLGs^YET09l9EQyF9zWkn6ROvk`O3jSh2kbPL) z8ciqz0I`i&C@O|hiE~3=tpKjJ$zyn_Z-N*`B`%1-ytOBSX$Us_e+6xA;^x}&oDG`U`)@##cfmEt zm?Y%gSbPNwKL{HwJWz$!P8$mQ>Iha()xfIKfPlUosk#FHwIUzL^MM_AWW0ajci;EzvS=^ce$Vq{nF4tqc|4KI0ObU;zr&KibFNxECsH?@;Bp?$&@BTh;$_4fUr#jr1X3}h$Td>Yaq4AvzW?&qdwiTNjNl0wmri5;q zSttip1{jo1Q83`ZW4!-c_0Fs@vIv~1PyEUpUtO8e-~4dxz0r-U(`z3s z>o+HjkAGK5p22~z9F7a(si0uIy#!pWFaKh7<-PUAtIiIVi5+HeHW3u`@i+DC!us_Q zb02eI*hl!@pcqc5(THHo&+5}ZFRx=5Wmr{Z;3b0BCf2_XQe@n{ZTlUk`&BRBwpEpgEP&myxSZKfT@C?Cj^FO^!U@o z){cB@N3Q2?Ye%8AJ5&Fu@5!R?K;Cy?>9w4{;Ol{C?|-J~-}ck2w&l|X zU-sw>J#+F;4f{$odZP2QM<)ShG+~sp(E*K(MIj%mdL7sUNfs~)jW3r40GU~ySnEZU zQ@4KS6~LBOvAvvR0H492gQFGm$A*omF%x<4U*qzkF+QSae!4OHKYA;^5Af2FiM6@k zZ@e`DYp&n=&HA0U^s$Qq)(OT{NG{4rgyrPq0^uo44eQtDOt%9=cp1)l9bSdQt`Cnu z-eS71o|y!ab<7}XCGm}9u3WOO4}4H=hYyF;H5Rjp6FUnTts+j%eOgjOU^diTL7vvw z3oyk_JenU)Jm#4K-%;fE=lT6h-!AaMB7Z2)A1d%K-u1jlT;&*qSDXTEh#&$@nkN)W zgyT{uq(9PXLQu^g-Ne-vjksnqUTPpM zhJB5idA@{joufBNZ5iPqNX4){v3lIJS~~nFD=)h<3rj&Y4=X`sEd;I7F0xJ&oChqR znu(Aq*SLv$mLarCZD9CMmxt}9vM-eou4nd}_0s-L(kI5IiFpV3^N$6*T2uLVMQ2iu zlY7Zv9MwSfbUuR#-pZ?-%I5g#1+5(#m12k&PvU!jKEY4o#r`c qy2v3J`yr+S=1#Y7=2ezWYDfyg6_H literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/.___init__.py b/sqlalchemy_fastapi_demo/dao/advisor/.___init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c30a4b13758dfd72932c8a28f59dcf011336bca0 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vf+zv$ zVAuh~%4k|Zrh~*K7#Kv8^K1M!>?9%-R+#R^5K#rdU0$*Bry`9;|ZnRz9t pz;0)LUSdv8r9w_>T8TnZPGVj*urCbNHKZw2|HHi^!yxznKLEpyIP3rb literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/._crud.py b/sqlalchemy_fastapi_demo/dao/advisor/._crud.py new file mode 100644 index 0000000000000000000000000000000000000000..b56f038ba11d6a269eb20979c98eae594b354723 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vf+zv$ zV3+~K+-O=D5#plB`MG+D1qC^&dId%KWvO|IdC92^j7$t?npgeUESkIrP3tIkGz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nu!jJsvkAgrAQzI6S*%c$TAW{6l$@%N ymS2>ukeOGKnpcvUpO=`EQ>l=XnpUEal#`g34eSd;bq#3>)&Fp>$S}zL{|^8>`za#; literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/._service.py b/sqlalchemy_fastapi_demo/dao/advisor/._service.py new file mode 100644 index 0000000000000000000000000000000000000000..b56f038ba11d6a269eb20979c98eae594b354723 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vf+zv$ zV3+~K+-O=D5#plB`MG+D1qC^&dId%KWvO|IdC92^j7$t?npgeUESkIrP3tIkGz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nu!jJsvkAgrAQzI6S*%c$TAW{6l$@%N ymS2>ukeOGKnpcvUpO=`EQ>l=XnpUEal#`g34eSd;bq#3>)&Fp>$S}zL{|^8>`za#; literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/__init__.py b/sqlalchemy_fastapi_demo/dao/advisor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d58d5e7ee7704b9559205ca8dd93cab1e31a27a6 GIT binary patch literal 188 zcmd1j<>g`k0>7QhvOx4>5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_~vsFxJacWU< zOn7EqN`859Oh9FFMq*KJKv8~HYH|sPUy_lZ2j!Z_6c^?s<|JpN=2ph1B^H+?7G%b! xq~_+wq$K9YB&L*Q7Uvhm#K&jmWtPOp>lIYq;;_lhPbtkwwF6mP%mgG@7yzV9GbI23 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..702933039796ccb8a4c3a193ee806805b40d588e GIT binary patch literal 198 zcmX@j%ge<81pYghWr66&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdngk^DLyJ?3iuE&- zQ_C~+^j%VmvrF;|^q*~Nel~CV)3wW<>|CIqmRMYpSdgh(P?VpQnp~n^T$q!Xlbn&7 zTNw|Picd++&DT#!%-2s$Da$O*FVc^X&&K5r~UH OjE~HWjEqIhKo$VQEjh^m literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-310.pyc b/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9af3db1f88fbb4138beaa95626d763c65d5c060 GIT binary patch literal 1862 zcmah}-HRJl6uB7$RcB4=)Dn|ku|VjZwksSVRKv5#x}3< z`jI)P^T*cm#ybRc99GafeCx;>H2C9MU&>AH@+Qcg^48eoEq(@G+A1uIKNPQQ^Rr;> zR;+jUE?75tqfa{R6<{YFn$`M3sUV)>_HF)Apkk?|$&8C>k}>{a=6Jb$6!6R~_fszt zzJZSvp9w3DOEA=nFeN0VDdY4yyJnly{hgr*)!b`-c zkRud@d~vBm>o80zTX5`c1P86w!5P3IrJT%&bRa-_<)n|HAqibj2p4LpypS4mme74T zUtwB~)>J-U$jy`$a${~S$Tc%H`(#Ob9XqqG&V)S7qiBzVFcGp6Fl!u0m2|9Aft1^T zOm5+Xam=SC?6Q^;p7bZB(N zHt4!h%P)f#Y8fe;*Rr80>uSp8gxpP8YK-W*wxObztS2$NkP&2rPLyn*;Gyzu$P(T| zw3{99O0B&B*A*6*3)oEh( zk9>~3pcl5Dtic}%JHJw@F@QSgIc($_)X5(HgY|my3~pLbV(TWTZ?i2+6O>pd+dgRx+YFrn^D?4fy>m6mKG3 WbsumcB`$5Vz4|$Kr}k96?feVFMWNsT literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-312.pyc b/sqlalchemy_fastapi_demo/dao/advisor/__pycache__/crud.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5cb895c83bf7919dd60e741cd927757d9ca88b5 GIT binary patch literal 2844 zcmb7GU2Gdg5Z=8Xpa0^xP2GkT_gA3YLu0j-8nq1tR9c!8%tJt}0wp!xHMzu&-93jY z=ps2HQWF&vkSYa4fj&W^f@JX&UQo+ZC0-mkQms?_1XSWJQQ)1~`|}Sj4J+O5?9S}W z-OM*L_iIN-5W%?l`gdd36@-4{8+TY7*lhj+(;^~>;4I4FVT?H~WQCkKECMZ3Oe881 znMxTS@y$xZGU>2R{nSU44?(ZRw<(aa&oX`zn3abW67e*&O87_+B>Y>{76RD->1?)~ zkw_TMgHwtc{gZ#0icMvR>bjPn;N;8X15M8}Qy}k|;gr1@nMmcRDHlfb6ErRIOU{sB z<@?Q9m=;kHJLky2hVVVUBiQ?C(LiI3_Z%@pyyM)!2qa|pc746$kQN{O);gLrh(kyf zlB&RbAjY_~Dlz_wrkEnc^riE;oK`dyMl+1+qrl`A>(Zv;e6P+g?T7LAyFet~(kasu zTAE(dCK9hueY}`2Bp(0x(c`Zd|M=nC-+#KD$fWdQs-PV%u>2TJ7Zdu`Y$}@`rMamQ zhc!ZIE}tN&e8RDjNV7@OTbME;+B?&J507Ta$LxLfcEpO}K`VX3&kDM$%lJJ2-8H>^Qi75du|` z4WT3&VhK<2Ab25kFCbKO!ibO?u4&1@GY1W+UC8RvV>}Km!@%P`O?rea=<&BGfvq95 z=n=P|$4%e{b%xlYM;hyBU^}D>!)e)&htM)ks){LJouq8a#+NUnWs8)tD9AV9NzQ0Y zFRDHpXU$C3#bv`V>D)~mZTt5#ZrhCLG{w@R9wK(aVTcQU0#gaqlx-E|na{J8y+_NF z<>^{yS1lM`=$Y@i*;ftjDV??W@me&t82&7L>*9lWVl|#9pInW

r6RlWR&>McLQD zKC&7=Qtn@kzgUgF#M$AB((SRox%|cDrL!PWjUEMNq-$Y(e*8ubu*k8-I^m6)Dgw_s z3trFK@Y*V%L;%!LL;U}M8Vi8MmO-$Azl7@il~-Rp;EIN@1v_nk@&r4=6YYrq1thCd znfN(Xv2nn&lI`FV2ZJePwQ*`yFeqKw?7u3Nb;+wzHflPunqG70jx+k1KtH)%b;K^tHB-a6omSe74-Ta-bZp zy5I^$7f#HdxN)i??XkL;2tMU`RnJz&gRaW$a@7nl&#_!VW3EmXNMrTh z$Jy}cgD|d(EoJiJ`5`xoH+JLpAbHDy!OCWmtVZ5jyw?om`h>-1X`E>j;*mW7bk0+T^>9NXX{EvedQo=5qHs z0`l&e`_jGh7FoIUcIBNbtCy~9a>mAPAKt|^!LoFwEG>f&karK=CHHzZIk^!H;TV^I crLHkn*BEQk7~9zG$2++^EVle#oV330A0r zq$YTqrFW>)7PY`*(gzN**S^EK$i{iiVL}8+45oDyr|bg{(#av`2?vkv^Nhl`zDF+t zk?^B9C-f|Dc*WEWXl|Bv>_yDiWY&4Bz}JAj4_$O%NYNNi(G*jBL$0-{Mp1@&ixLNY zHdAy<9r4RvLt2e3OH{< zRBmPGbd|C!CLK{c*OGs@yrxXG|AGPfuT*;0V8YnfL8sd6T=FfBkRB#OosocR>Gkmw2;Ced+W z0TH?0wp$?hh0?YY9&rh&zv^UHexds3%gB40+y+f<&ox>6iC+9KQb*GO_$^>YL_f^EZiL4!Kh5C?M1;uWmfu;D8T`1GctxYz`#Cy}# zN(w28_~?UBpCk{WEmbH!t^a}GOU5ls7+Mha1NJSD_1$xCXEq5$@IublJ@v;z`dUTk5m%z4g+lKx2nWbP4lbh#&ST7FsVr6Gyewq7tW?yz3bI15qY`yX zakQ_Lye4#==)$HsF|frV8~DUQkMA0p#50~Mg9Ck?FjjP{ASwmA;{cDp@7ymkm)@!d zlCv2Y_Jz7ptQMrOK+d3eB*U-wBaj1B$H2rX4SI#P25R7v5-J1i7knIg?@0}5AMXyv zi9W}GzlakXFofdh=*PT1ID2wKUPnh#4!Too+isO)RLZLfOh#;4*xm?xq0tNsN@`#-qu5Wbq;}E2KN<&#k zG!Abvnt+7>3{8N6P67$cotiU%5<1RZ)eCTNhYN&g0wME3d?$hvyx)|%5ApD<= z?vH96Wu)AZ)bBncg$w48GU@LUy$qolU-_v0DQHD{+B1?i$@}7M){n?b_H^=TECbR zFZ2kBQpEIvShnIiJ7w}NeHE_we;~UJq$^{L&r$juy?u_Bx|)hp-+t0Xzz(nUIO|R% f@JrkT>@X$RgLsc?-B)D%9_Ck^AEurQE>ivrGw52T literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/dao/advisor/crud.py b/sqlalchemy_fastapi_demo/dao/advisor/crud.py new file mode 100644 index 0000000..f48ee0b --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/advisor/crud.py @@ -0,0 +1,56 @@ +from sqlalchemy.orm import Session +from model.advisors import Advisor +from model.students import Student + +def create_advisor(db:Session,advisor_id:int,advisor_name:str): + advisor = Advisor(advisor_id=advisor_id,advisor_name=advisor_name) + db.add(advisor) + db.commit() + db.refresh(advisor) + return advisor + + +def search_advisor(db:Session,advisor_id:int|None=None,advisor_name:str|None=None): + if advisor_id is None and advisor_name is None: + return None + query=db.query(Advisor) + if advisor_id is not None: + query = query.filter(Advisor.advisor_id == advisor_id) + if advisor_name is not None: + query = query.filter(Advisor.advisor_name==advisor_name) + advisor = query.first() + return advisor + + +def list_advisors(db: Session,advisor_name: str|None =None): + query = db.query(Advisor) + if advisor_name is not None: + query = query.filter(Advisor.advisor_name.like(f"%{advisor_name}%")) + return query.all() + + +def list_students_of_advisor(db: Session, advisor_id: int): + """查这个顾问名下还没被逻辑删除的学生""" + return db.query(Student).filter( + Student.is_deleted == 0, + Student.advisor_id == advisor_id, + ).all() + + +def update_advisor(db:Session,advisor_id:int,advisor_name:str|None=None): + r_advisor = search_advisor(db=db,advisor_id=advisor_id) + if r_advisor is None: + return None + if advisor_name is not None: + r_advisor.advisor_name = advisor_name + db.commit() + return r_advisor + + +def delete_advisor(db:Session,advisor_id:int): + d_advisor = search_advisor(db=db,advisor_id=advisor_id) + if d_advisor is None: + return None + db.delete(d_advisor) + db.commit() + return advisor_id diff --git a/sqlalchemy_fastapi_demo/dao/advisor/service.py b/sqlalchemy_fastapi_demo/dao/advisor/service.py new file mode 100644 index 0000000..bdffd80 --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/advisor/service.py @@ -0,0 +1,41 @@ +from sqlalchemy.orm import Session +from sqlalchemy.exc import IntegrityError +from dao.advisor import crud +from scheme.advisors import AdvisorIn + +# 成功 (数据, None);失败 (None, "错误码")。 + +def create_advisor(db:Session,advisor_id:int,advisor_name:str): + exist=crud.search_advisor(db,advisor_id=advisor_id) + if exist is not None: + return None,"DUPLICATE" #ID主键已被占用 + try: + advisor = crud.create_advisor(db,advisor_id,advisor_name) + except IntegrityError: + db.rollback() + return None, "DUPLICATE" + return advisor, None + + +def update_advisor(db:Session,advisor_id:int,advisor_in:AdvisorIn): + exist = crud.search_advisor(db,advisor_id=advisor_id) + if exist is None: + return None, "NOT_FOUND" + u_advisor=crud.update_advisor(db,advisor_id=advisor_id,advisor_name=advisor_in.advisor_name) + if u_advisor is None: + return None, "NOT_FOUND" # 查过之后被并发删掉了 + return u_advisor,None + + +#删除成功返回Advisor ID,删除失败返回None。顾问如连接学生,则拒绝删除。 +def delete_advisor(db: Session, advisor_id: int): + exist = crud.search_advisor(db=db, advisor_id=advisor_id) + if exist is None: + return None, "NOT_FOUND" + # 查一下这个顾问名下有没有学生 + if crud.list_students_of_advisor(db, advisor_id): + return None, "HAS_STUDENTS" + result = crud.delete_advisor(db=db, advisor_id=advisor_id) + if result is None: + return None, "NOT_FOUND" # 查过之后被并发删掉了 + return result, None diff --git a/sqlalchemy_fastapi_demo/dao/c_lass.py b/sqlalchemy_fastapi_demo/dao/c_lass.py new file mode 100644 index 0000000..524820c --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/c_lass.py @@ -0,0 +1,66 @@ +# # dao/c_lass.py 数据访问层,直接操作数据库 +# # 本文件封装对 Classinfo表的所有数据库操作(增、删、改、查) + +from sqlalchemy.orm import Session # 会话类型,标注db参数 +from model.c_lass import Classinfo # # 导入ORM模型 +from scheme.c_lass import ClassCreate, ClassUpdate # 导入入参模型 +from typing import Optional, List # 类型注解用:Optional=可空,List=列表 + +# 新增班级 +def create_c_lass(db: Session, obj: ClassCreate):# 新增函数:接收会话db和校验后的数据obj,返回Classinfo对象 + db_obj = Classinfo(class_id=obj.class_id, start_time=obj.start_time) + # 把前端传来的数据组装成一个ORM对象(相当于内存里的一条新记录) + db.add(db_obj) # 把对象加入会话 + db.commit() # 提交事务:真正把INSERT语句发给MySQL执行,写进数据库 + db.refresh(db_obj) # 从数据库重新查一遍这条记录,把数据库自动生成的值(如默认值)刷新回对象 + return db_obj # 返回这个对象,方便API层序列化成JSON返回前端 + + +# 根据 id 查询单个班级:只查询 is_deleted=0 未删除 +def get_c_lass(db: Session, class_id: int) -> Optional[Classinfo]: + # 按ID查单个班级;Optional = 可能查不到(返回None) + return db.query(Classinfo).filter( + Classinfo.class_id == class_id,# 条件1:班级编号等于传入的id + Classinfo.is_deleted == 0 # 条件2:没被逻辑删除(只查0) + ).first() +# .first() = 取第一条;查不到就返回None,不会报错 + +# 分页查询所有班级:过滤已经逻辑删除的数据 +def get_all_c_lass(db: Session, skip: int = 0, limit: int = 100) -> List[Classinfo]: + # 分页查所有班级:skip=跳过几条,limit=最多取几条 + return db.query(Classinfo)\ + .filter(Classinfo.is_deleted == 0)\ + .offset(skip).limit(limit).all() # # 只查没删的; 跳过skip条,取limit条,返回列表 + + +# 修改班级(局部更新:传了哪个字段就改哪个) +def update_c_lass(db: Session, class_id: int, update_obj: ClassUpdate): + # 修改函数:按id找到班级,把传进来的字段改掉 + db_class = get_c_lass(db, class_id) + + # 只取前端真正传了的字段 + update_data = update_obj.model_dump(exclude_unset=True) + # 把前端传的修改数据转成字典;exclude_unset=True = 只保留前端真正传了的字段 + # (没传的字段不出现,就不会被误改成None——就是"局部更新") + for key, value in update_data.items():# 循环:把字典里每个字段的值,赋给ORM对象对应属性(内存里改好) + setattr(db_class, key, value) + db.commit() # 提交:把改动写进数据库 + db.refresh(db_class) # 从数据库重新查询这条记录,把数据库里的最新值刷新到 Python 对象上,让内存里的对象和数据库保持一致。 + return db_class # 返回改好的对象 + + +# 逻辑删除:不再db.delete,设置is_deleted=1 +def delete_c_lass(db: Session, class_id: int) -> bool: + # 删除函数:不是物理删除(不删数据库行),是打标记 + db_class = get_c_lass(db, class_id) # 先查这条班级 + if not db_class: + return False # 查不到返回False,API层返回404 + # 打删除标记 + db_class.is_deleted = 1 # 把逻辑删除标记改成1(=已删除 + db.commit() + return True # 返回True表示删除成功 + + +#DAO 层是所有 SQL 的家,API 层不写任何 SQL,只调这里的函数。 +# 查询统一过滤 `is_deleted == 0`,删了的数据还在数据库里,只是查不到 —— 这就是逻辑删除。 + diff --git a/sqlalchemy_fastapi_demo/dao/employment.py b/sqlalchemy_fastapi_demo/dao/employment.py new file mode 100644 index 0000000..8fd2b32 --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/employment.py @@ -0,0 +1,175 @@ +from fastapi import HTTPException +from sqlalchemy.orm import Session +from sqlalchemy import and_, Date +from model.employment import EmploymentBase,EmploymentOffer +from model.students import Student +# ========== 就业基础信息 DAO ========== +class EmploymentBaseDAO: + @staticmethod + #根据学生编号查询 + def get_by_stu_id(db: Session, stu_id: int): + record = db.query(EmploymentBase).filter(and_( + EmploymentBase.stu_id == stu_id, + EmploymentBase.is_deleted == 0 + )).first() + return record + @staticmethod + #多条件查询 + def different_choice_query( + db: Session, + stu_id: int = None, + company_name: str = None, + min_salary: float = None, + max_salary: float = None, + skip: int = 0, + limit: int = 10 + ): + # 基础查询 + 过滤未删除 + query = db.query(EmploymentBase).filter(EmploymentBase.is_deleted == 0) + + # 动态拼接条件 + #学生id查询 + if stu_id is not None: + query = query.filter(EmploymentBase.stu_id == stu_id) + #公司名称查询 + if company_name is not None and company_name.strip() != "": + # 模糊匹配,%代表通配符 + query = query.filter(EmploymentBase.company_name.like(f"%{company_name}%")) + #工资范围查询 + if min_salary is not None: + query = query.filter(EmploymentBase.salary >= min_salary) + if max_salary is not None: + query = query.filter(EmploymentBase.salary <= max_salary) + + # 分页 + result = query.offset(skip).limit(limit).all() + return result + + @staticmethod + #新增学生就业基础信息 + def create(db: Session, obj: EmploymentBase): + + student = db.query(Student).filter( + Student.stu_id == obj.stu_id, + Student.is_deleted == 0 + ).first() + if not student: + raise HTTPException(status_code=400, detail="学生不存在或已逻辑删除,不能添加就业信息") + db.add(obj) + db.commit() + db.refresh(obj) + return obj + + @staticmethod + #更新就业基础信息 + def update(db: Session, stu_id: int, update_data: dict): + record = EmploymentBaseDAO.get_by_stu_id(db, stu_id) + if not record: + return None + + if "company_name" in update_data: + record.company_name = update_data["company_name"] + if "salary" in update_data: + record.salary = update_data["salary"] + if "employment_open_time" in update_data: + record.employment_open_time = update_data["employment_open_time"] + if "job_time" in update_data: + record.job_time = update_data["job_time"] + # =========== 统一时间校验 =========== + final_emp_open = record.employment_open_time + final_job = record.job_time + # 两个时间都不为空才校验 + if final_emp_open and final_job: + if final_job < final_emp_open: + raise ValueError("job时间不能早于就业开放时间") + + db.commit() + db.refresh(record) + return record + + @staticmethod + #根据学生编号对就业基础表进行逻辑删除 + def delete(db: Session, stu_id: int): + record = EmploymentBaseDAO.get_by_stu_id(db, stu_id) + if not record: + return False + record.is_deleted = 1 + db.commit() + return True + +# ========== 就业Offer协议 DAO ========== +class EmploymentOfferDAO: + + @staticmethod + #添加就业协议记录 + def create(db: Session, obj_1: EmploymentOffer,obj_2:EmploymentBase): + # 时间校验 + if obj_1.offer_time < obj_2.employment_open_time: + raise ValueError("offer时间不能早于就业开放时间") + db.add(obj_1) + db.commit() + db.refresh(obj_1) + return obj_1 + + @staticmethod + #修改就业协议表 + def update(db: Session, stu_id: int, offer_id: int, offer_time:Date): + """修改offer""" + record_list = EmploymentOfferDAO.different_choice_query(db, stu_id, offer_id) + if not record_list: + return None + record = record_list[0] + #查询就业基础信息,拿到就业开放时间准备做时间校验 + base_record = db.query(EmploymentBase).filter( + EmploymentBase.stu_id == stu_id, + EmploymentBase.is_deleted == 0 + ).first() + #避免就业基础信息被逻辑删除了而就业基础协议记录还存在 + if not base_record: + raise ValueError("未找到该学生就业基础信息") + #时间校验 + if offer_time is not None: + if offer_time < base_record.employment_open_time: + raise ValueError("offer时间不能早于就业开放时间") + record.offer_time = offer_time + + db.commit() + db.refresh(record) + return record + + @staticmethod + #根据协议编号对就业协议表进行逻辑删除 + def delete(db: Session, stu_id: int,offer_id: int): + """offer逻辑删除""" + record_list = EmploymentOfferDAO.different_choice_query(db, stu_id,offer_id) + if not record_list: + return False + record = record_list[0] + record.is_deleted = 1 + db.commit() + return True + + @staticmethod + #多条件查询就业协议表 + def different_choice_query( + db: Session, + stu_id: int =None , + offer_id: int = None, + skip: int = 0, + limit: int = 10 + ): + #基础查询+过滤未删除 + query = db.query(EmploymentOffer).filter(EmploymentOffer.is_deleted == 0) + + #动态拼接条件 + #学生id查询(选填) + if stu_id is not None: + query = query.filter(EmploymentOffer.stu_id == stu_id) + # 同时传了offer编号 → 查单个(联合主键两个都查) + if offer_id is not None: + query = query.filter(EmploymentOffer.offer_id == offer_id) + elif stu_id is None and offer_id is not None: + raise ValueError("不能单独查询offer编号,必须同时提供学生编号") + # 分页 + result = query.offset(skip).limit(limit).all() + return result diff --git a/sqlalchemy_fastapi_demo/dao/statistics.py b/sqlalchemy_fastapi_demo/dao/statistics.py new file mode 100644 index 0000000..588c5ce --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/statistics.py @@ -0,0 +1,110 @@ +from sqlalchemy import func, case +from model.students import Student +from model.Score import Score +from model.employment import EmploymentBase,EmploymentOffer +from model.c_lass import Classinfo + +def students_age(db,op:str, + age_value: int = None, + age_min: int = None, + age_max: int = None): + + a=db.query(Student).filter(Student.is_deleted == 0) + if op == ">": + a=a.filter(Student.age > age_value) + elif op == "<": + a=a.filter(Student.age < age_value) + elif op == "=": + a=a.filter(Student.age == age_value) + elif op == ">=": + a=a.filter(Student.age >= age_value) + elif op == "<=": + a=a.filter(Student.age <= age_value) + elif op == "between": + if age_min is None or age_max is None: + raise ValueError("区间查询必须提供 age_min和age_max") + a=a.filter(Student.age.between(age_min, age_max)) + else: + raise ValueError("请使用 >, <, =, >=, <=, between") + return a.all() +# 多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。 +def class_statistics(db): + a = (db.query(Student.class_id,func.count(Student.stu_id).label("total"), + func.sum(case((Student.gender == "男", 1), else_=0)).label("male"), + func.sum(case((Student.gender == "女", 1), else_=0) + ).label("female")) + .filter(Student.is_deleted==0).group_by(Student.class_id).all()) + list1 = [] + for i in a: + list1.append({"class_id": i.class_id,"total": i.total,"male": i.male,"female": i.female}) + return list1 + +# - 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。 +def score_above(db,score_input): + result = [] + for stu in db.query(Student).filter(Student.is_deleted == 0).all(): + if stu.score and all(s.score >= score_input for s in stu.score): + for s in stu.score: + result.append((stu.stu_id, stu.stu_name, s.exam_id, s.score)) + return result +# - 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。 +def score_fail(db, fail_times, fail_score=60): + result = [] + for stu in db.query(Student).filter(Student.is_deleted == 0).all(): + fails = [s for s in stu.score if s.score < fail_score] + if len(fails) >= fail_times: + for s in fails: + result.append((stu.stu_name, stu.class_id, s.exam_order, s.score)) + return result + +# - 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。 +def avg_scores(db, order="desc"): + avg = func.avg(Score.score).label("avg_score") + a = (db.query(Score.exam_id,Student.class_id,avg) + .join(Score.student).filter(Student.is_deleted == 0) + .group_by(Score.exam_id,Student.class_id)) + a = a.order_by(avg.desc() if order == "desc" else avg.asc()) + return a.all() + +# - 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司。 +def top_salary(db, n): + a = (db.query(Student.stu_name, + Student.class_id, + EmploymentBase.job_time, + EmploymentBase.company_name, + EmploymentBase.salary).join(Student, EmploymentBase.stu_id == Student.stu_id) + .filter(EmploymentBase.is_deleted == 0, Student.is_deleted == 0) + .order_by(EmploymentBase.salary.desc()).offset(n-1).limit(1).first()) + if not a: + return None + return {"name": a.stu_name,"class_id": a.class_id,"job_time": str(a.job_time) if a.job_time else None, + "company": a.company_name,"salary": a.salary} + +# - 统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)。 +def stu_every(db): + a = (db.query(Student.stu_id, + Student.stu_name, + EmploymentBase.employment_open_time, + EmploymentOffer.offer_time) + .join(EmploymentBase, EmploymentBase.stu_id == Student.stu_id) + .join(EmploymentOffer, EmploymentOffer.stu_id == Student.stu_id) + .filter(Student.is_deleted == 0,EmploymentBase.is_deleted == 0, + EmploymentOffer.is_deleted == 0).all()) + return [{"stu_id": sid,"name": name, + "days": (offer_t - open_t).days if open_t and offer_t else None} + for sid, name, open_t, offer_t in a] + +# - 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)。 +def class_avg(db): + days = func.datediff(EmploymentOffer.offer_time, + EmploymentBase.employment_open_time).label("days") + a = (db.query(Student.class_id, + func.avg(days).label("avg_days"), + func.count().label("count")) + .join(EmploymentBase, EmploymentBase.stu_id == Student.stu_id) + .join(EmploymentOffer, EmploymentOffer.stu_id == Student.stu_id) + .filter(Student.is_deleted == 0, + EmploymentBase.is_deleted == 0, + EmploymentOffer.is_deleted == 0, + EmploymentBase.employment_open_time.isnot(None)).group_by(Student.class_id).all()) + return [{"class_id": i.class_id, "avg_days": round(float(i.avg_days), 2)} for i in a] diff --git a/sqlalchemy_fastapi_demo/dao/students_dao.py b/sqlalchemy_fastapi_demo/dao/students_dao.py new file mode 100644 index 0000000..4862bc8 --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/students_dao.py @@ -0,0 +1,115 @@ +# dao/students_dao.py +# 本文件封装对 model 表的所有数据库操作(增、删、改、查) + + +from sqlalchemy.orm import Session +from fastapi import HTTPException +from model.c_lass import Classinfo +from model.advisors import Advisor +from model.students import Student +from scheme.students import StudentCreate, StudentUpdate +from typing import Optional, List + + +class StudentDAO: + + @staticmethod + def inspect_class_id_unq(db: Session, class_id: int): + """校验班级是否存在:去 c_lass 表查""" + return db.query(Classinfo).filter(Classinfo.class_id == class_id).first() + + @staticmethod + def inspect_advisor_id_unq(db: Session, advisor_id: int): + """校验顾问是否存在:去 advisors 表查""" + return db.query(Advisor).filter(Advisor.advisor_id == advisor_id).first() + + @staticmethod + def create_student(db: Session, obj_in: StudentCreate): + """新增学生,检查学号唯一性""" + exist = db.query(Student).filter(Student.stu_id == obj_in.stu_id).first() + # 只按 stu_id 判断,且包含逻辑删除的记录 + if exist: + if exist.is_deleted == 1: + raise HTTPException(status_code=400, detail="该学号已被占用(处于逻辑删除状态),请先恢复") + raise HTTPException(status_code=400, detail="该学生已存在") + db_obj = Student(**obj_in.model_dump()) + try: + db.add(db_obj) + db.commit() + db.refresh(db_obj) + except Exception: + db.rollback() + raise + return db_obj + + @staticmethod + def get_students_all(db: Session, skip: int = 0, limit: int = 100): + """分页查询全部学生""" + return db.query(Student).filter(Student.is_deleted == 0).offset(skip).limit(limit).all() + + @staticmethod + def get_student_by_id(db: Session, stu_id: int): + """根据学生编号单条查询""" + return db.query(Student).filter(Student.is_deleted == 0, + Student.stu_id == stu_id).first() + + @staticmethod + def query_multi_condition( + db: Session, + stu_id: Optional[int] = None, + stu_name: Optional[str] = None, + class_id: Optional[int] = None, + skip: int = 0, + limit: int = 100 + ) : + q = db.query(Student).filter(Student.is_deleted == 0) + """多条件选择性查询""" + # 只有参数不为None的时候,才加上查询条件 + if stu_id is not None: + q = q.filter(Student.stu_id == stu_id) + if stu_name is not None: + q = q.filter(Student.stu_name.like(f"%{stu_name}%")) + if class_id is not None: + q = q.filter(Student.class_id == class_id) + + q = q.offset(skip).limit(limit) + return q.all() + + @staticmethod + def update_student(db: Session,stu_id:int, obj: StudentUpdate): + db_obj = db.query(Student).filter(Student.stu_id == stu_id, + Student.is_deleted == 0).first() + if not db_obj: + raise HTTPException(status_code=404, detail="学生数据不存在或已删除") + + update_data = obj.model_dump(exclude_unset=True) + for field, value in update_data.items(): + setattr(db_obj, field, value) + try: + db.commit() + db.refresh(db_obj) + except Exception: + db.rollback() + raise + return db_obj + + @staticmethod + def delete_student(db: Session, stu_id: int): + db_obj = db.query(Student).filter(Student.stu_id == stu_id, + Student.is_deleted == 0).first() + if not db_obj: + raise HTTPException(status_code=404, detail="学生数据不存在或已删除") + + db_obj.is_deleted = 1 + try: + db.commit() + db.refresh(db_obj) + except Exception: + db.rollback() + raise + return True # 返回布尔值,而不是 dict + + + + + diff --git a/sqlalchemy_fastapi_demo/dao/teachers_dao.py b/sqlalchemy_fastapi_demo/dao/teachers_dao.py new file mode 100644 index 0000000..15c0baf --- /dev/null +++ b/sqlalchemy_fastapi_demo/dao/teachers_dao.py @@ -0,0 +1,67 @@ +# dao/teachers_dao.py +# 本文件封装对 Teacher 表的所有数据库操作(增、删、改、查) +from sqlalchemy.orm import Session +from scheme.teachers import TeacherAdd, TeacherUpdate +from model.teachers import Teacher +from model.c_lass import Classinfo + +class TeacherDAO: + @staticmethod + def add_teacher(db:Session,teacher_data:TeacherAdd): # 前端返回的teacher_data是1个Pydantic对象 + db_teacher=Teacher(**(teacher_data.model_dump())) + db.add(db_teacher) + db.commit() + db.refresh(db_teacher) + return db_teacher + @staticmethod + def inspect_teacher_id_unq(db: Session, teacher_id: int): + """ + 根据教师ID获取教师对象(用于主键唯一性检查,查询结果包含被软删除的对象) + """ + return db.query(Teacher).filter(Teacher.teacher_id == teacher_id).first() + @staticmethod + def inspect_class_id_unq(db: Session, class_id: int): + """ + 根据班级ID获取班级对象(用于外键检查,查询结果排除被软删除对象,即不包括is_deleted=1的对象) + """ + return db.query(Classinfo).filter(Classinfo.class_id == class_id,Classinfo.is_deleted==0).first() + @staticmethod + def delete_light(db: Session, teacher_id: int): + """ + 删除教师 + :return: True 表示删除成功,False 表示教师ID不存在,已被软删除或硬删除 + """ + db_teacher = TeacherDAO.inspect_teacher_id_unq(db, teacher_id) + if (not db_teacher) or db_teacher.is_deleted==1: + return False + db_teacher.is_deleted=1 # 标记为1逻辑删除 + db.commit() # 提交事务 + return True + + @staticmethod + def update(db: Session,teacher_id:int,teacher_data: TeacherUpdate): + """ + 更新用户信息(只更新传入的非空字段) + :param db: 数据库会话 + :param teacher_data: 包含要更新字段的 Pydantic 模型 + :return: 更新后的 User 对象,如果用户不存在则返回 None + """ + # 只更新客户端显式传入的字段(exclude_unset=True 排除未设置的字段,不排除设置了None的字段) + update_data = teacher_data.model_dump(exclude_unset=True) # 返回要更新字段的字典 + db_teacher=TeacherDAO.inspect_teacher_id_unq(db, teacher_id) + for key, value in update_data.items(): + setattr(db_teacher, key, value) # 动态设置属性 + db.commit() # 提交事务 + db.refresh(db_teacher) # 刷新对象,获取 onupdate 时间等 + return db_teacher + @staticmethod + def get_all(db: Session, skip: int = 0, limit: int = 100): + """ + 获取所有用户(支持分页,不显示软删除) + :param db: 数据库会话 + :param skip: 偏移量(跳过前 skip 条,从skip+1条开始返回) + :param limit: 最大返回条数 + :return: 用老师对象列表 + """ + return db.query(Teacher).filter(Teacher.is_deleted==0).offset(skip).limit(limit).all() + diff --git a/sqlalchemy_fastapi_demo/database.py b/sqlalchemy_fastapi_demo/database.py new file mode 100644 index 0000000..e5425fb --- /dev/null +++ b/sqlalchemy_fastapi_demo/database.py @@ -0,0 +1,24 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import declarative_base, sessionmaker + +# 1. 配置数据库连接地址(注释掉 SQLite,直接使用 MySQL) +# SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" +SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:123456@host.docker.internal:3306/0914tw" + +# 2. 创建 engine(数据库引擎) +# 注意:MySQL 不需要 connect_args={"check_same_thread": False},这行要去掉 +engine = create_engine(SQLALCHEMY_DATABASE_URL) + +# 3. 创建 Base(ORM 基类) +Base = declarative_base() + +# 4. 创建 SessionLocal(会话工厂,必须在 engine 最终确定后再绑定) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# 提供数据库会话,接口通过 Depends(get_db) 自动获取 +def get_db(): + db = SessionLocal() # 创建一个新的数据库会话 + try: + yield db # yield = 把会话"借出去"给接口函数用(执行到这里暂停,等接口用完) + finally: + db.close() # finally = 无论接口成功还是报错,最后一定关闭会话,释放数据库连接 \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/main.py b/sqlalchemy_fastapi_demo/main.py new file mode 100644 index 0000000..eeb4880 --- /dev/null +++ b/sqlalchemy_fastapi_demo/main.py @@ -0,0 +1,49 @@ +from api import statistics +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from api import Score +from api import employment_api # 导入 employment_api 子路由 +from api import teachers +from api.advisors import router as advisor_router +from api.c_lass import router as class_router +from api.students import router as student_router +# 从刚才创建的 database.py 中导入 Base 和 engine +from database import Base, engine + +# 现在这行代码就不会报错了 +Base.metadata.create_all(bind=engine) + + +# 创建 FastAPI 实例 +app = FastAPI( + title="FastAPI + SQLAlchemy 分层架构", + description="学生信息管理系统 - 班级模块", + version="1.0.0", +) + +# 注册班级路由,统一加前缀 /c_lass +app.include_router(class_router, prefix="/c_lass", tags=["班级信息管理模块"]) +# ⑫ 把班级路由注册进应用,统一加前缀 /c_lass +# 所以API层里 @router.post("/add") 的完整地址是 POST /c_lass/add +app.include_router(employment_api.router, prefix="/api/employment_api", tags=["就业模块管理"]) +app.include_router(Score.app_score, prefix="/api/score", tags=["成绩管理"]) +app.include_router(student_router,prefix="/api/student", tags=["学生信息管理"]) +app.include_router(advisor_router, prefix="/advisors", tags=["顾问老师模块"]) +app.include_router(teachers.router, prefix="/api/teachers", tags=["老师模块管理"]) +app.include_router(statistics.router,prefix="/api/statistics",tags=["统计模块"]) +# 根路径 +# @app.get("/") +# async def root(): +# return {"message": "欢迎访问!请访问 /docs 查看接口文档。"} + + +# 直接运行此文件时启动 uvicorn +if __name__ == "__main__": + import uvicorn + uvicorn.run( + "main:app", + host="127.0.0.1", # 改成本机地址 + port=8004, + reload=True, + ) diff --git a/sqlalchemy_fastapi_demo/model/Score.py b/sqlalchemy_fastapi_demo/model/Score.py new file mode 100644 index 0000000..8983c9d --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/Score.py @@ -0,0 +1,18 @@ +from sqlalchemy import Column, Integer,ForeignKey +from sqlalchemy.orm import relationship +from database import Base + + +# 成绩表表模型 +class Score(Base): + __tablename__ = 'score' + # 联合主键stu_id,exam_order + # 外键关联student + stu_id=Column(Integer,ForeignKey('student.stu_id'),primary_key=True) + # 声明关联student + student=relationship('Student',back_populates='score') + exam_id=Column(Integer,primary_key=True) + score=Column(Integer,nullable=False) + + + diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ca8c528ad53774107a40ff4907e41246f1fb403 GIT binary patch literal 738 zcmZ8eO>5jR5S9GBj&~_(PCfOym%SEBDWQRcPzZtT2MB{uJZjd7WIK{g>t54q{zGr2 ze@WM#`WJfY$h)v<1sctJBaPn7wDWmRaGihuaq}!7yNJs+Yca{euXEm;T?)O=uEAJ z8TqXoUAo@JkzZVi>XvtHH=uTDPm#)+K`C*i}Hu3H$C_Y2PN2BCJ5 zIp@8;+DJX}Pr~-1t2s#BmZ(;$a%#+~8%>JI{k8>~ zj70P>EP{eQp;P2yIdl0w)Bi;*_Mug4^i+&{z9;|rc?AOdfx|Zmel?}v*SGbaV!&mu Twhetvy)55|BT~?U9z}lv`bWd$ literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-312.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/Score.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..913657dac6808cf52bae27a26a770dcc057479da GIT binary patch literal 869 zcmZ8fJ4_To7@pa^ecW<@F(UX%EF|ZecpHgY7-OR1;Um(Zh1*P)n-Lafc9+?`=vtkT z!jcYc43&?7iLtY@x6ycoOhSxNN$fC4@67E1(ZBfS`ycbqH~-9s-d+bttCANp0~!F| zm9uR|mu%K0Sp*nhNCAUBWSXxr-PfUtX|%))-{^3in#}So2sAJTaA_W3gILRY(Z{!Q z)3tsn$JK>-Ii^h(3F}&vktxE3Q;#_br=lAqccG|oLW3-fqjWkno)lC6>(D*uZebT$Z<1=9i0Iox1Iq(~Vgx z_D)?-UUnT}Of;liVWet#(3fUSOroqNR}|t~QgBbgLl*EH&5~SL6GdLe`zC|NEK1^} zDep(px(wM-lhR<4l5w{pY=okK5rl+;5Q}k>DqcZot{Kp7rWc`1)fX;T^W`N4>cxav zh~R2K!s;p$4!IvN6mv{CS5N*5Y)S-McO-bXQ^Hd(Y><0l4}fSXFeZ1`~Gyh=W46|tuplFz?*8ja;`PD+CQ)`_3~J|-)mi8 zb@nU_E)BPx;}5U!!R?;oZdo|HLjIpa-)^cFb5_jb=x*>I;WZq{k;*^DmC{1@e#JVc v4M`^K^Tl&q;D@EFzEyfe!iEkZ{0c@sfsr*(T?427*fw+@k8T0EbhiHm*l6wN literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8056c90921ca39eba9b2fa38a63631600dac964 GIT binary patch literal 786 zcmY*X&2H2%5VrH5G`s47L%DI?%O1EORR|SYfw-VbTZFJ8S>D)m)7nXDJD@$6Yaf6Y z0PzAmjIW&f3Y-`xi?)npYrb#nnfdJLX0rl;{rdjn>RX7=Zx0??1mFagIfsoSjwMov zAng4>Vik};g(OrFiBwGDkq>2}Qj(5-Br}zh9HTdg$2|Fpcp~!KkQ6*!p+$BNS&lG&zf&8F!AN3WO>wa@m@ zVgM(w%rR^N5zG+@I3}TpM9c#o^5`xk380k6w-|787m!TkJmr{Y;1@iHJ`0z=;fn!FEksYoSDI@1H_RudE%UWNRs0y0Qa@2$1tNtFLL_ z^#h0y=H24JWt6r|2})f-sp|M3y3pdc(9j*WHzuZbm05nIC`=nU?Th4xY>@3BvsJ)a)<1qL*>SE3_a;xc#?`~~ar B)<^&V literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-312.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/advisors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de89e7642398c2e24fe525f623bb2bc2d4c0ebf1 GIT binary patch literal 1081 zcmY*YOH9;27@j`1?LL8pL`;bX(HKQzj3}u1-~xDPOq#MYK%pU&(gm_R$xM`5PGwnWflK%bv$9(@kU#DO4`3#_|55Akvivav! zPIILiVE-WnD*yt>*}wrh;27p@&f#_55p=;3bj!k|XPKj73{<(t4T$Jh%;D zY8gNYr8k6xSI?AXRoP>X$`J*cAqp)AsUneXdUoWvL>_ZPG>b5iCPHkvvqTx8MU$+E zBRPz0GqgN6n6rH9i#N;wl@jX2w&s6B{S|eNC=X;Yq|Jqu*#gwOY1(<=^TCNrADCgAzk%!@9 zEATK;%mf6JDo?ULwj2|ejRjODc{2(<%PnE#AUE7QPkY>A0=kiHo6|Ph>!A^q$DQ;= zq{y`vBc_)O(To|{A(1D-2-2NIZnU7u!n9dhFnrICsHP|wS38Mf7_R9c!yp;Ma6A~< z4Cf4EF*5B&CT|!aYniy1ULb&(>Lk;kHY|uG7RWUNtdykuInPB{X7%hg5W)49NR}Rn zb~o59zzPd1K{9Hv4)&=J4jxgXO$7)CnpHwemaC1RU?KE;ZTI8T-PbES@8ACXw5rXR zL1_BcSs#1zs1$0!qHWrxIpma$M#_N5@iclYWNS^O2mLb6(gv|%vjtPsEQ4=7eU%4W zU5Bdj+T>@k-ZfgeyVZU8<*C);t21k;-hH8Re=ApfezAJu#g)})bEKZTTp8Ue_Evk> zPJb9!AE*~ERqp*(Kj65$ISu z_}|F}>EC2d(;ot-n~m^shT^^_DI&_%^RN;OKWS^c4(kgZ>?G R?vI$}hPh|(0I+w=@fQ{|D0Tn< literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..342dcde4af4c8d13c57c93a544965ff8d6887eb5 GIT binary patch literal 813 zcmY*XO>fjN5Ouz@+3bo#PjKOy%U+QXLWm*|mujUJRf<-!+{`SS)=svzqq1kX_J6=% z@)dF5FK}X;r=sl5Y$W%)Ul-4(U0ovfsqQs>r3My&P2MvX7m`&!}De zPFSo0S89~PwtZ)I?VjTJtuWa5Q;!EJom8y}AgcplbqGNnVT=ic^hEbjol=x}758DC zkC_-!$S5Ig}$VVL>XFZgwh#F>SZ)UD|MuFRIYZ_qtU=ANUO(T+()c zU*40%yc?txR}ytVYN}Ar>E$xOtr(`TF@t#9Pq*3SD8W z(3aa)p(|R$0VP@l?K|mmGf6Zqx04R@gXyQ9%P)T}PhW068PsNTNv``lvsoXSozQBn z`)h2hkL|AS9>NzJb1Q`;Kje5TsPew0f~wz;36z_uqpSTvXT+YE?R+E|M$IbtWuRu_z=x@>~6&vY~7AN$K5-xu=wfeQcP2<&_ Kkf<^^iT(l*d*C?$ literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-312.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/c_lass.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec05cf23a15a77dfeaa1dbfbf690534e8c86dbb4 GIT binary patch literal 882 zcmY*X%}W(g6u)=A-}B=o6fRUK2;xD$A!wIGrkDn~$u_gOT;ILw=$#MmouS^&$aT2W zRk-Q{4WwOvL#yCzx*!yl(5^6P+nE`C*1(+ko%5UdopXM7J`4=h5nN;J)#`H#p|3@9 zcG;)kcm}{WVu)dZA{^kz2#m-KOkC6qVMTUem)I0eKo2g` z_8Li(G>0|0((VGM?G-SY(?%C0c?eA}2etW;`FHz7;!|_xmtGu20YF$tPOTe0^6k$9{e3+aIzjCaVc4Q6Y z%P0lQ&4aAlnAn*8G&HF#(%CNJpK_~KSb9K(T(3u4Nu}N>jV|gQsOU^Rr+@T literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/employment.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/employment.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3267ea8040c0f97bf624ba926467ee7efa95f86d GIT binary patch literal 1096 zcmZuwOK%e~5VrT7?WPH(2Obx$x#YqD300_~P=t_5MT?M3B+HGRcFTI5dN)GLHC+2U zP=62?Upe(JaAIb+G~uz4$Npy4GhgPLHT`}{;CcN0+xgfh>YsgAQ zk&E_BvCyT9UzfEyRn|pEwav>@7rYR)a^ZeqMD5ajV^w}yzERDHy5PB})D#n}KOul! zSk*f)iZCh(^CV@y3RI{f=`AS|yYyKMo@7Z`?`BV7-;m*wf-i$}ANEbyfwqhWC zCKg3~FdDjq^HONVxl1|MMlK3GXPjRwL~#@8b6$&+LUqu3mzxa~Dw zX0A$J=UTbs+?=#0i_*GmYV=%`O;l2^puhfr&Ne%yOHd0#18 zO+MtMG@q-;OGT*xo_2g=VG9U4SlWFT*r++N2#sMeIF% z{kFZ`=>hs4g2B{P1_pbP{q6%sps-62^*g^ymEkz7PNRzgnYD|xG)`%L+hzw>%CbJ@o*^$kh z$YIT>sp1-`%e=^At*E8Ak@~D1wKb%pD~Oouh*-3})2PpiI?8K<*E!~$s+xiOP=*AW za0o7GnJ^kS!tZhlET&m6$*8d2&(i_RgnczDX^(PYeOmG)>j`HLq84F|aOZPQlV0{A zt%M=H!kkZYTn4&m6|^XlJY#qbmQE4cO)owewtT|W~Izmbm*9?i!9#OgxBW@!@P>uX!VdlI$Y)m6E>kMc#xJ0K}R@ooMA@e zSh#V_axzGz-HPLz1Dqbs_;Fm~<&@Tx%X)ANKv+dNh!eu4zQohVQpo!>i)H_Wvzjj} zi`z1&)y-KSXO%jXd-Wz5dQb^BDPlrXT2gWw9l#8F^cg^Sy`a1ZlP>)-$-+5Wtd)5` zy#LEL_rKq|_wx^b|GFKn;G)F+yEA=Z_>m00xbY4|c1~^fw((x))vvGdmq&Y_kQ4j`)pu|MhW{z2lM=I)ES#}S zl%zn0#;!S*iCbBLEjkmKe6q446+gLsoJ-FlpMf-#GWaR576Ol-mYy>b&PsSz!no=D zIiSK(i^sipYbra=&&lwYB&hqJm)6A*JOf7YCV;H+g(s>EwY~C_vFBfc@Hn4rffT$s+`Vs@uPRg?(E9 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/students.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/students.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b6ca43fdb37a82c465b8554ad496bf461d5d98b GIT binary patch literal 1408 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 ebM8mx+%L@j`^@J1%N literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-310.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93e975a157ce44d61fa75739037059b83f63a20d GIT binary patch literal 1170 zcmY*YOKTKC5bmCtotd5NBgTjkFP@AGVGmveNkT9Z5g`N;5r>6lGTq5e(lfK^o+a$! zK}k+R@Z>?nyE*8=laQa`t*?oX`~^=|?SrfhRb5|qb=6nZ-FdYd5Ewt|pZ5-JLe3FP z4hO&rh<*%;6HX;bX-HEmv{E~?QzvvNu3NH{x}iI;ZRw?c=u`59aEF(U2`>r%$PUZg z-6Rd~5+ad?W8BqTcGJvwPqRYo3T1+|T!~~idnS6u-7Hj+?KY^XC?TUF$ur$fI)I%= zkrpw=m>eYlDuVR8E+sTbT;-Vo{Z99thStsvwp`Sv>cy>I{ zE`zLs=)0geeMR=jN4Qv+Da3+BI+cJi!^VgITx}u zN~)Wkp79w|qN5nAV{a@_cWHlmYk0@a@#cDC8a0(B+Y6~+#_ksR$*87uI* zhfrZS1^8=y>(Xy7MBA-HmJ!5ef)XmtyHum=-r4xtaq1JM}S zCl0O989EJ81FJ#@`|FLs1Xrz?pfg~CBuwpUznQCanEuYy;(z^X@(9X<52`TrAjbr+ X0Zk-l{Ka8^mhs_fq&jCIt6A$G^IkxF literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-312.pyc b/sqlalchemy_fastapi_demo/model/__pycache__/teachers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce574400310f5119800c6a2ce958272d6ab82bf1 GIT binary patch literal 1455 zcmZuxU1%It6uvV%J3G7CpT?xtS|afw#+A5>LHdw36^x{sHo=fB$RJ)Ob8phw%wO*8 zBD<(vF%RO4ibxWQ5`C~KNu~5j$xD1{!IzaT*bMZkX|!*Zwe;09Ft{2U?C985r zj+qHdQ56A+=sY6Q5+ZS`Y=CdR)MQQ0CmwMzFZuGAV^%HOPrPGS=sab9YTRMen71#` znlH~(m|@T71wYNGsZ|We_AVPPoTWE4kLuhftJKK<^5YK+ycHNNgUxL52^p-iL#m8_s|6vX_6vco9X?y8IoB- zYPOcm=ln#8YWihJIZ+9O5+v5;GQ-kX4KL7IJ*Q(+^Spx25gTM23>3R+n%b;M9}UB; ztET{Vf7$x`=UWdNpZ@jb4Ul)Ywm^RP#r3^!SMwsvfQ6sX9m}G2#ZQiLUxq#B_(~Yo z1FzXxO<%yS<5r=})YHR?bn21>N2uH(j>1)#0bs)V9Oi(D0V5sO1u`%a zFj4Og82}UiE;)np@>IR|Y*?w6!y7{>M(e4es4S!P+)%{Wnngzk>*>LvvNMarQ*1DQ z4rVPC85zV^qM!YAq~*rG68*-9%%kR<$4k-wy@iV77WZy_ zw)g$=!y7;C{<>D2)4Yo28n3#{DO0^t^cGFcgeF@x98#E2%PCq8p=L3R>=oRauVBom z%P_7VD+S|Fh%{M{p!`Ib6k(eb-{sq}X^zQhu?@b_6pSQXf>!}!KZP;ev1)QT zjqzetGeahWafQ!caAbTk7;i1><-i{dcANumDtng02@VMW7(+gN)ML-X={jP3df7=1 z{0Zs+xAS6wcN~)+6uoh1SaX{R!-fVXr;YeJm=&bbf1o_l+5*v_Jn%X(1^x~4dXY=}x%$f4ptR@M01$k> lJZ|wgCJ4e)83||ZqLKS(@IHF&Ur7 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/model/advisors.py b/sqlalchemy_fastapi_demo/model/advisors.py new file mode 100644 index 0000000..4e4d1ac --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/advisors.py @@ -0,0 +1,14 @@ +from datetime import datetime +from sqlalchemy import Column, Integer, String, DateTime +from sqlalchemy.orm import relationship + +from database import Base +#创建顾问老师表模型。 +class Advisor(Base): + __tablename__ = 'advisor' + advisor_id = Column(Integer, primary_key=True,autoincrement=False) + advisor_name = Column(String(50),nullable=False) + #引入时间模块,得到创建时时间。特别注意这里,datetime点now不能有括号,有括号时,就在创建这个表类的时候,就锚定了时间。 + #不写括号的话,就是当这个生成实例的时候,也就是具体往表里面注入内容的时候,才会生成一个对应的时间。 + # 反向关系:Student.advisor 的对端(属性名必须是 students,与 Student.advisor 的 back_populates 一致) + students = relationship("Student", back_populates="advisor") diff --git a/sqlalchemy_fastapi_demo/model/c_lass.py b/sqlalchemy_fastapi_demo/model/c_lass.py new file mode 100644 index 0000000..7189683 --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/c_lass.py @@ -0,0 +1,23 @@ + + +from sqlalchemy import Column, Integer, Date # 导入"列"和字段类型(整数、日期) +from sqlalchemy.orm import relationship # 导入"关系"函数,用来定义表间关联 +from database import Base # 导入database.py里的Base基类 + + +class Classinfo(Base):# 定义ORM模型类,继承Base,SQLAlchemy才知道它对应一张表 + # 表名必须和建表语句一致:c_lass + __tablename__ = "c_lass" # 指定表名,必须和MySQL里的表名一模一样,否则连不上表 + + class_id = Column(Integer, primary_key=True, index=True) # 主键列:整数类型;index=True表示建索引,按这个字段查会更快 + start_time = Column(Date, nullable=False) # 开班日期:日期类型;nullable=False = 不能为空(数据库层面强制) + # 逻辑删除:0未删除,1已删除,默认0 + is_deleted = Column(Integer, nullable=False, default=0) + + # 反向关系:Student.my_class / Teacher.classes 的对端 + students = relationship("Student", back_populates="my_class") + # 声明关系:一个班级下有很多学生(一对多)。"Student"是字符串,指向学生模型 + # back_populates="my_class":和Student模型里的my_class属性互相呼应 + teachers = relationship("Teacher", back_populates="classes") + # 同样:一个班级下有很多老师 + diff --git a/sqlalchemy_fastapi_demo/model/employment.py b/sqlalchemy_fastapi_demo/model/employment.py new file mode 100644 index 0000000..9c09520 --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/employment.py @@ -0,0 +1,20 @@ +#导入创造引擎、定义类模块、数据类型模块、连接符模块 +from sqlalchemy import Column, Integer, String, Date, Float, ForeignKey +#导入基类 +from database import Base +#定义就业基础模块 +class EmploymentBase(Base): + __tablename__="employment_base" + stu_id=Column(Integer,ForeignKey("student.stu_id"),primary_key=True) + employment_open_time=Column(Date) + job_time=Column(Date) + company_name=Column(String(100)) + salary=Column(Float) + is_deleted=Column(Integer,default=0) +#定义就业协议模块 +class EmploymentOffer(Base): + __tablename__="employment_offer" + stu_id=Column(Integer,primary_key=True) + offer_id=Column(Integer,primary_key=True) + offer_time=Column(Date) + is_deleted=Column(Integer,default=0) diff --git a/sqlalchemy_fastapi_demo/model/students.py b/sqlalchemy_fastapi_demo/model/students.py new file mode 100644 index 0000000..a2d2af0 --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/students.py @@ -0,0 +1,41 @@ +# model/users.py +# 本文件定义 User 表的结构,映射到 MySQL 数据库 + +from sqlalchemy import Column, Integer, String, Float, ForeignKey,DateTime,Date +from sqlalchemy.orm import declarative_base,relationship +from sqlalchemy.sql import func +from database import Base + + +# model 类,对应 student表 +class Student(Base): + __tablename__ = "student" #指定表名 + + stu_id = Column(Integer, primary_key = True) #主键,学生编号 + stu_name = Column(String(10),nullable = False) #学生名字,非空约束 + native_place = Column(String(30),nullable = False) #籍贯,非空 + graduate_school = Column(String(50),nullable = False) #毕业院校 + major = Column(String(20),nullable = False) #专业 + enroll_time = Column(Date, comment = "入学时间",nullable = False) + graduate_time = Column(Date, comment = "毕业时间",nullable = False) + education = Column(String(10),nullable = False) #学历,非空 + age = Column(Integer,nullable = False) #年龄 + gender = Column(String(10),nullable = False) #性别 + # employment_open_time = Column(Date,nullable = False) #简历开放时间 + # company_name = Column(String(100),nullable = False) #公司名称 + # salary = Column(Float,nullable = False) #薪资 + # # 逻辑删除标记 + is_deleted = Column(Integer, nullable=False,default=0, comment="0正常;1逻辑删除") + # 外键:关联 C_lass 的 id + class_id = Column(Integer, ForeignKey("c_lass.class_id"), nullable=False) + # 关系属性:关联 Classinfo + my_class = relationship("Classinfo", back_populates="students") + # 外键:关联Advisor的id + advisor_id = Column(Integer,ForeignKey("advisor.advisor_id"),nullable=False) + # 关系属性:关联Advisor + advisor = relationship("Advisor", back_populates="students") + # 关系属性:关联成绩(Score.student 的对端) + score = relationship("Score", back_populates="student") + + + diff --git a/sqlalchemy_fastapi_demo/model/teachers.py b/sqlalchemy_fastapi_demo/model/teachers.py new file mode 100644 index 0000000..e3c2962 --- /dev/null +++ b/sqlalchemy_fastapi_demo/model/teachers.py @@ -0,0 +1,16 @@ +# 与数据库的表进行关联 +# 导入database文件,这里已经创建基类 +from sqlalchemy import Column, Integer, ForeignKey, String +from sqlalchemy.orm import relationship +from database import Base +# 关联数据库中的teacher表 +class Teacher(Base): + __tablename__ = 'teacher' + teacher_id = Column(Integer, primary_key=True) + class_id = Column(Integer,ForeignKey('c_lass.class_id'),nullable=False) + teacher_name = Column(String(50),nullable=False) + job_name=Column(String(50),nullable=False,comment='主讲、班主任、助教') + is_deleted = Column(Integer, default=0, nullable=False) + classes=relationship("Classinfo",back_populates="teachers") + def __repr__(self): + return f"" \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/requirements.txt b/sqlalchemy_fastapi_demo/requirements.txt new file mode 100644 index 0000000..593df71 --- /dev/null +++ b/sqlalchemy_fastapi_demo/requirements.txt @@ -0,0 +1,5 @@ +fastapi>=0.100.0 +uvicorn>=0.23.0 +sqlalchemy>=2.0.0 +pymysql>=1.1.0 +pydantic>=2.0.0 \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/scheme/Score.py b/sqlalchemy_fastapi_demo/scheme/Score.py new file mode 100644 index 0000000..a436e5a --- /dev/null +++ b/sqlalchemy_fastapi_demo/scheme/Score.py @@ -0,0 +1,15 @@ +# 请求体 +from pydantic import BaseModel, Field + + + +class ScoreCreate(BaseModel): + stu_id: int=Field(...,ge=1,description='学生id必须大于等于1') + exam_id: int=Field(...,ge=1,description='考核序次必须大于等于1') + score: int=Field(...,ge=0,le=100,description='成绩必须在0-100之间') + + +class ScoreUpdate(BaseModel): + # stu_id: int = Field(None, ge=1, description='学生id必须大于等于1') + # exam_id: int = Field(None, ge=1, description='考核序次必须大于等于1') + score: int = Field(None, ge=0, le=100, description='成绩必须在0-100之间') diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/Score.cpython-310.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/Score.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fac3f5afb297ffd665fef8ba78f44fec43c8cb3 GIT binary patch literal 902 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 V%k9-=y4$7F6N_){5tyPo{|yv9b~pe4 literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-310.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43a80c5b199f0bccadb27945942a08d8b278c066 GIT binary patch literal 3019 zcmai0TW=dh6yA&1d$AomXq|pLz4bRu=Q5}Fb#Kn6AY1v>`Q@c%YkAmfoiKk!7j+?S9~of+QmS# zHGx%M4-DG~Oxu*D*CkRQ+Bu16R6eWP7T_Y$0qX*n02{;vYzkZkY>^V+lE4+fWl{lL z5qJ#n7^woT3S0$TBjbR_1+I~a6H7r6O~8`HNULVd2i=24&UYJkW&`soNO!RHvnPGUtcyy`e^7)FVUn~fc3Nn$k|MDuU+=u6F+n6kL}o)?nn zgSdIT+nRS-aGXV_Xe&XS%tv7#zR-+M`>x-br$N`5b>qZsdk&#N)Qr(bn>0JbRJ+Si zN@ciXRE;G~%EGffQ4N^(AfjwNBThx)Yy+?(-)2DJP3fgYi6@2qz?D{V2*2@gf!zyUT(Ck2ykab)@3Y@}%eU@+ za&hhI&l^{73+_4xaCrIF>YeMom5wbZ9jtB>narUFx;&-onfA^b14XA;6d3#XmB028%>sdTQsl-25>OO zvtXv|mM1_1du4_rLn_Fs@Eb7tzbcSH2dN5B8ATCWT_^xl0UiV5YC>GCp(4}|EZYm8 zVf)bFnLAivL|ID1%#E~0c|?#a!0Me(dy8L;3>?1Qs9W1o$`0a(L?%6kPokb-DI3Y$ zAs9FScZ|#`luK`iH2)<)?A-^I&r7D0DI+qoCj~^fD+t1p=iR z8gReCpH*y-9MGck{W&eiu%`)b-l1_D+7eAE%Hln=0Zd)oz%unUr>*pC~qDHr1i?3HkvW8OF}2*pTPc z664qzvCbE1SzypLgi9v|{J&&CxGI8ClkdwJ#lATltw!4XvTi3z+|brH1IOyHbqLhK z2P~V#i9HRIN79CTPUGNVG>GbB+lOGFJLg*+D9PJKX$n5@BHS@HdkeyzcIO&K3db7t zac;D`#0?X##T4)`j1@zbFswIBM}tz}#iZNz!nrhaO>|?!7j0ftc~P_&rk@ajSbr1; d+&Gf{=l3#l8{?sND>b|{xb&J)E7r_O>pzp0mn;AP literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-312.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/employment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20c0609fa28506bdf9237ddce58b0f4fa682d788 GIT binary patch literal 3662 zcmb7GTWlLu8lJId#^ZY~E-et6i`&2eiFYY1Edqon(7U6h4HAAC4Vja4ipMr*#;}%n z2x=>};?h(Ck|JR9vP%ouRagNVwB6lTBwixf56Qd|C+!mzF+$>r|3Bl5$0oq;Nb}D* z-+$&@{>yj%ujBCu2hYINM`!YJj{62XTaVamY_33KmeV<%&vPc9!}fCwWJF#vpm! zNt)PGU)J)5uGvNEBqtGX0ZPCTKtmiErEQo55P7U*8^wZ_cZB1HWly;0b!GGL+~)nz zpXCUb<8>|<80Sck2s-~Lpn4!D5{ZOvhc;kA#3}*U-;SrvQodL*Nx>eQoFsI-#FmyU zyQ~^|)`=7mRoO0NM^@E>W)f9(BB~1KDCe;qQ`MKsTE3|X8U@=)s;X8f6m1PRZK*0v zz=AZ4A_U?Zw+WK_UImdEw+OW|#sqoAC}f@@){Azrlv)4B+4T=+>wo*}+L!a0NzJmg zk}*=E#WQ5W&R8$ywfw|sVpi0qO4W&3%vgw#4DpUMTB^_(tiePdG^`yU&T}iVm!gJ^+upWELG8D#&ga0oL}V6~^Z>Imp9=vdH!)^q7#9XC(!>O2 zd0r8nRLk-hBd+1IPO7zgwOAqrW_l+!Q8Y_hp~B4XNS2n@Xhn(AByPG3MK=muq-AB= zi`_dwI6=#%^iFJvllh`%(-f-Mk#ED+t}QVH4Qm7h80o&uvaoCJp7{r_j8=ur%Fyui z@tJ$(_FW#S3d1YAho+yoaCm0?;#f@>a%aLx+KlJr`p2O08!rH%sq=bZA^1rERPf}$ zltj{*d6-tzC7(7#WD;(gFoY&#V`Lb?v){Q~goNS$u&0aY(S?{ddz8dL8~3!lp3svE zT^?`5NdolU%sHac)9IXplt3zuevh#PF}d;fpEs_*Tfg+rYrGTHi8VnDmYo#Hj?0$O zto6Ttc=O8n`dk01FMfLCwKvvhzqmR3nIoSmzQ7z>9>6h+pRO&vSHC{J{`P;|0pDJK zum0s{BkS*97+IhF3v=g99Y&Vf!tU_%3-wD&*8)z&)c&OANny%9P0?%2(G<;D?)N6Y z@$SbrK0o*E^*7f3`@zOLR~}gV_nY;_OY83}0;L3|Z1+cu3nkeZO9IY`2ckVFSS+Qn zG^VSHt;5+PDSC$m@zE0Ld3 zY%`eX0BnK|qChK`qaYaBx}oLBF7p~Xb0_PpExlg9ba~rQL4M6Dk^jYs_u`U_kCBQy zeT6QfC?0^s>^5TiAFt9pw_f=u3_p8y`(DN-mejeEwFS8w&lgQ4kUQHNw zoq@BqIm63_CqUzOMyqUKEq1j5J2%S)R`amB%VSrmA}JxKuVvgZEE<@FpCwiaDgfdd z+6%q5jWj8o+r*2kwGoU7s8NDHrhjeX(Syapq%n0Wdrj!@1{7AbXsViRQ{#oQO{@-M zJCge=#YjH{?oyAw6zY9f|I< zCsw*rRU!3*z>EFgaUk5)aCn`ny?SgBct2)c;u1XvWX z7)u>ti_M^_4najLd)|$M6T;4&Ehk{P@^j~A-RmF?6T4RtUI%T*`7J*W{mK%ao9RAW zpd)RV2Oa^%NmTv;1zy4waV7D~?!%M&?z7h3(P6&(Y&#F{#~~<=!)sxAxaHxFx~V_i zy3f+TSVdKZq0V@~$+JqgBbO?=Rp~tM3LEH-RJpY5l@rU^;cW8r4Z*YURqy#TF z_5}Fhxg!k@K8;wAPtP4_aPVm)ME(?y9sD+Wg8XqFhvB!85cs=ij0OjvMvuhz&%-eI TG*U9Ol?Df&TetP{Zdv&gfn-=m literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/statistics.cpython-310.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/statistics.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91bf2c883fc40175ec322599d1f7491bb2302b31 GIT binary patch literal 2046 zcmah~&2Jk;6yMoh+v`o7gw~XTN>$3IIk*>8q$)ybqrwSOsVYd8rPazaNu2J7JF{CF z#GxVuA&~&$Lj|c95LKv9;Xq4K`S?TThUlirnHvY-_jVoEC5gJ$Jk9UDH#6_|=Dl%T ztGNcg=l@t+{KqzoKM9O}&>1rr>H-8eI17xBwOMGk&CqIF%y`A%Cbupb+!AcrYTLjz zF9DZwTmmlh3UDRIWnhO_fvY*L0K0q)cr3>b@Hnpl*K%Ct6Q_;FH!)^0R3GAPV-Z)9GFitAv{I%fF*9@B z-UI}f**h$n7+4K;a9}m$VOUMFZmpC@hbw7Ddh@I;kHXI?{6NZXr7z&zVYJyND_dla z47g+~w>K}}xbySs#`163$1CfXf6A_ZkzM&VeHaT1p2ie762kXCCyL0=)yT81@e*J4G8@8lcl@5t2gmz!2oSl?1&NHS& zFn7(6lQ8|=nLXAyql8qQH+m6|-&CDbOWg%uhNon_D7p#ZWFd|Q@WqZg7x+PUL4-@* zoR912_dG7bxT8oXI?yCNmGru**QanC!K`axll7BySsmt?d z541y7?t!b^OM;SJBxgU(sIKHb5|2S>OC@q719?L7G&}+;`6>#+HR|jDlcd|00Ls@4 zhMI=ho&avI;*}F6q@Z{e%6LVJ6d)PH6qJh;obJX_jHF3FJLx(!L1U89tTVMQG7$*>>9OCg@s zrnZu}zgq~;!v6swJOh_Qgjx+( zJN+f@M|f!@J@!SV=N(RknU`#Sqj|#euqCbBsT#C1UA!$X(O-v}fT$Z&=G2}k8$YXV F{Rine#c%)s literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-310.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..959d48de5466e57763cb3c65c722da2019a0f29d GIT binary patch literal 2167 zcmaJ?OK&4Z5bmCbJs#V!lQ`KV3#(n;!y`xt3523mL?k#7R=Y$(HPMZzaIbE2xp9-C}nMpIMuRd;nw*H=AxyX_OW-u&&m zQ`RKpcQlqS2aJ7q6bHcxrwK`ENK-4cQaiLMVpig$PUxg==o;HjYH2;JQ}Qn14tKvG z+!gfP4n44IybgBV*bT5f-T=E{Y@hoNNYI?ZN+hs#0?YgzHX<7CVcQ zm`6n}1510Lh$2pfc2Enb_TC>Aah^rV0OKrQE*Sgps2U|ikdSf`T1Q0KoN|lXkF3xU zuBdTmZyBo_%&jo^f=BQz2K6em!F@m*!iV|I3T+v*Y0!3st{Ajs&`yPx5!wdrR_Ll3 zyJFC_8M@AUd;?bNm>f2*jP07SH%j!JhO1%?a@wlwbz^Vu5xxVveN(p|6k{&3;y?=6 zz}+eA4Y{D&8VX%g#hArhdxIoW3bgS{;GBN@>-3xN|M=|l%OAgt`Jcahb@{_jmp^}f zJK|@t%B9+!DKI{;B#?^eCKqZTV^bLIFZ@#^--V_9G|pHevSD!odi2R$_b`DhO2zaR zhG}I{5uXV*N}_?7zJ^d|C?h_G#F-kLvqD4s%5L-90-3nE`c9mU__ z!CUig^aW<4@K|CHzsZE6Ime$^0c}CvF%~V)~9__-aUAudy*ZK!zXwusN literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-312.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/students.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..827f45ec4a7c6029e5061a0faed3d0908f3b5edb GIT binary patch literal 4293 zcma)9eQZ(=FmsH+2yC25uwgb~ z2pbZ{u#rWXA}IGn-eYJ7M3wE-(m#rHY1os_P$Z`6}C{R8Kf;bX)Bdl zK-#L4TC>)mt%?(aMz!@MFNqT=L5!=W@t7DFRA&N5ksEwGCh&5K1P!VM7*UQTM3qA> z$f}leX*rfk^6{vafJW;pd%)t#L?+A%OxSPTSra0_h< z)tdBL!MxDYSTEIEn)Iy;*1En`w1RhAlise=+o;~rq;J#d?Nsk<((C;@sJ^{P-=Uk| zM)fY8-Ys|*I_vp4Y5rcF-XQ4bx6}FCn)E)M{|>6}LcQpMm2Rh;8@O)dgr2ZR>=fNy zs5c9}b!{JVu-{%`$3p*oI3;|9f!oY|jb*~yvOPh+>bNLp1TiU(5)lr3e-$n7v8rKO zRLzo{iNple5{>hc1YBk>D67Bus51B)mBl+M8PbTta{MEl;E$XNYw>=bvKZEwUi8T zQ8n_o$Z0Vth@>i@wLO|jr1@l)28H$Wah_yVo0uf2cszo*m{cA0kQ65#F_Dg^vI*G2 zNGdHRsg-Ktr(}@;d^p5dw6^^af?*KI_`lvpq4Oi=DoQs!Hv?PCL0W^Ae!?}75u3aL zN+>fM2mTWlW|;N18vhOb7@GWi-3{}cJhzDYwLFb_{}-7cH<{T7QPw{A<o03__ntm@YxT}=SO4%kP5$}Ao7!Jy56t-V{oLwXKV5y8TYLMX=g-Rw zKhOM~cOi^Ed_7E%Bl!N1At0*tbv~XEUn3+%NDu^g(2^LRlJKDWzj^~`=#nH7DHMx} z-;X6jW1@6TPNhR@f4sH!>p57&(+`WGDPEHKbZlRmq^^olIV4?=Lz%rICbE&5Dk6x9 zR0v*eF(HNk3$sLK@`14-?bn5ni1U4U`>#20?9F7m>GNf6I<_!t#{cLEIZv# zoC7P)f#TScz{pBq6y+yFhgOCTJ+>YC*wwS# zds=awS+<{{`mKB&UkMz4>^zRX23}XZmzUcwf8un{*w!HlCg@Ww5sIuxM72gDfQ(FB z1l}HrT+i@v1bQSwI4~t`KvZKaDXY#%gij_@GR3q6dMD~Tka($)BopGp;dUh5NP3a@ zkqjc)2}Ctb#Z$aYT2Md_(t;d9hP(je9zzZwA3}mQZiU-J^PFcF-z>R~Xqg__h&WpE zy{bigwQTRWHBs*9RJhLa;81QNf4DGq_hp3}DsS&oxV|sVjJdOLxn$b;rNLqHtQ#5g zF3M?}g!{8~JFp!p(Kl%a=ylbiZwfXlLD+&9W=-GJ7U)`vR-KKxcG1zcLugsB)URGE zSlMcxTAQq_IxD-*YI7UW@a521H8&Ibh;2Hnwx)@{mI)`~Q_k3wjuhY2-!) z!tmq>l1Aw{ibEuLt4T+-($h0g49uS|^@IS>r}7tPCloGJ=^HGL{puPNl`DB^Hlc9A zO8?HHFn_(&e*lV)rQp8nP`CrsZ1Mb~7fXHP4cqaGe`uat>Ucy-{xeV#b{B^4?o+rk zm7RO$N0v_f)nD2<0fp$hh3MTk6mEigUcCP3LaF~$?(~N5Q&_eloX}L@N2uHZnO|?(Qa1P(7epzYN9bxicNoK5*nmtAgRtN zl1hMonZ(}A$fC6AU02Q8RB{3$oq~S}p>dmmD`?iK9o;AhCWEb;9FqnlDMBd_vE3wS zzbOhijxr>;rxLF94pX)}Z=Ef-!F`Iz=`OeXG`RGZ+wfj=!QG2^*ir6;yBZI3(MJXFd7T&lvc5HqJWPLpXq+X8{MhBOm*UfghUae*r)07{UMm literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-310.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a082938a22c7a9df006f74e8992a3b4b5306f08f GIT binary patch literal 2249 zcmaJ?|8EpU6yMq1yW89Q(xa3Lh_Qb66bt^OA&sfxm-vH~2xzitvRQ71cANcj% zmP)1q&p+$0%*+^yavP2QM+ajZS~LxUDwKGNPb@-ES3T8NEmi88r}?_2OI?RC87t#w ztt?UAQ)q@}k190FGEL3Oft{lU*oL$Xu=CUe+mv>m7IrJu;tH&$REfyE>oSjmVo)b$ zvFkI`Kdi@Y7&u;475TTEhdxw zq1|~A#1tg&CGx2{N9NRngb&7$z;o((g=%x;yz;f)B%hHvvRi5Cjn`rL(uIpFS5J=g z_CAvQb!_Eg8%P*QLD;r>_-*OYM;3oSv3O&?sx=VQexw?CaI6k*U>c@V8tXxQ$O?@O z;P1u*Fp^tmlFt{C`I|dNT11#1J6?mm!+FSCn$T)qB*;OLb389R#Ar+5NYua9&K;9` zBgUi2PuzfphoZ?{v$bi5`@48J!)h_w@pKq;&DSQQ1D@kS_W85+ekY2Zx(l%S;beq9 zHrdUGXtX{n)^)EKvwM5TbKHUQp%}VBhKNoMZ|TeBHNz*W1H!OnPT00EZQBoN!(*Tq zZTmpO@i1F#nuaaz1SZ=kNWNA*; zjSS06ztOE7Q2%H_){b6J5qhAaK%Ic9Ld)GcQKFEZ09~nz?cO>T#R-nU^AZY7v=o&A z)G8bee)!YLC`T yL|tU#*}5A{aY;H}B6(Bg9plKAocyr$gfW)Zh&K>CNp+DF)gq~=l}x2FRQ?YU9Z(Gb literal 0 HcmV?d00001 diff --git a/sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-312.pyc b/sqlalchemy_fastapi_demo/scheme/__pycache__/teachers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..573591365ed4a2d148f53e38c5493f6084f8bbfe GIT binary patch literal 1896 zcma)6%}*Ow5P$n&d%da#75Ri+u=!hASbIFz*IU{o} zgH0$Ca>ALgKt$3*%+Ld3hH2=j6u8SoxHJM%rB14FX%wVtoitjEY4L45s0n_k+oHA! zL@^DIdX__x4-`BrpEGPt^rLSZF1?jEsqH66&{qG@uq`movuqGNz}laE0pGKPl8j)I zj5q}OQpprd(Ug|tTD~$3(Xbin1lyWET&It4eWXsWEJdG+L8y#Eqi|ZS)5gsBQljQv z<@yHH7n53}uim9bc8s#?rrEJAfOO&&fX$h2tIN}UU7K@1Y|i|&IrDt$$Cc{i&lg2s z9HoBDq;8g3yb!+X1rBt}+{2?=Up?FUW#L~(eI;ufu8UUjT7c@pH`UUYivml4$d4a* z${7yb#vj@{1F*5Y^85EMUQT`ro`G+ytN^cmwg@>wKB{BoberZzy|KWHGM*pS(L=u$ z^A(*_UH4U8ckz&5*}Z$y2H>s^nr zQ@|F<4j|ck4U`)=ds`Sgh4dPc#zTwwWe zn)TA|ecQ01=uT1JSLr5o@@W@kG`(L2x1&&GQHa0+i{=ghJS6L>Q*)_#VYQ>DlIoqj zIqjC^-u0%Ik~?RtUV5j})IHfdeWxsUuQ#{OU3qe?(tLID-BPM7U*$&g#_F55D@}uF zRFMbSxq}G*J+hyG`u~mWX|SY`BZC`Wiqs8eh(`Bql)CYZn(9)lZafdI;(SO2E#W8j zhjgfbH?g1LBf^phF$CVBCS)fNuvhFPLNh`O0(MP{F^tbz5pc4C*7MVNMcJzeXA!uI zHe`5^wIiHEcn#sg0bn?{2LPJVc45Bj$?et7p-S65sO?zEedLtod+X;fK9QF@D(Cy4 z32)3@`TBBM?&HSKudm*CztUzL7*}K?h=J~pG(!dfuAQ3z_06CXl}!Q5#F@xh2xL-? z$;b}h#acVU#fYZ($^F6(QnvupPWe4JoOu5CM^eET0@n^!?JyNn$Vf#|lm2cw=CI>N zJ~v{G-tE`qW5tIjljR-V@H}P>Pk7WlR%JgN9Ay_F5;nz+06ZXTt!OE~&XTWm2G7zpb_tBJyzW~7e@KEL uR7q= self.age_end: + raise ValueError('输入起始值不能大于终止值') + return self + +class ClassCount(BaseModel): + class_id: int = Field(..., gt=0) + gender: str | None = Field(None, description="可填男/女") + +class ScoreCount(BaseModel): + score: int = Field(..., ge=0, le=100) + num: int | None = Field(None, gt=0) + +class ScoreAvg(BaseModel): + exam_order: int = Field(...) + +class Employment(BaseModel): + top: int = Field(...) + +class EmploymentOff(BaseModel): + class_id: int = Field(...) \ No newline at end of file diff --git a/sqlalchemy_fastapi_demo/scheme/students.py b/sqlalchemy_fastapi_demo/scheme/students.py new file mode 100644 index 0000000..3e1e07a --- /dev/null +++ b/sqlalchemy_fastapi_demo/scheme/students.py @@ -0,0 +1,58 @@ +# scheme/student.py +from pydantic import BaseModel, Field,model_validator +from datetime import datetime, date +from typing import Optional + +# ---------- 请求体模型 ---------- +class StudentCreate(BaseModel): + stu_id: int = Field(..., ge = 1) + class_id: int = Field(..., ge = 1) + advisor_id: int = Field(..., ge=1, description="顾问老师id,对应 advisors.advisor_id") + stu_name: str = Field(..., min_length=1, max_length=10) + native_place: str = Field(..., min_length=1, max_length=30) + graduate_school: str = Field(..., min_length=1, max_length=50) + education: str = Field(..., min_length=1, max_length=10) + major: str = Field(..., min_length=1, max_length=20) + age: int = Field(..., ge = 18, le =40) + gender: str = Field(..., min_length=1, max_length=20) + graduate_time:date= Field(...) + enroll_time:date= Field(...) + + # @model_validator(mode="after") + # def check_time_order(self): + # enroll = self.enroll_time + # graduate = self.graduate_time + # + # # 两个时间都传入时才校验 + # if enroll and graduate: + # if enroll >= graduate: + # raise ValueError("入学时间必须早于毕业时间") + +class StudentUpdate(BaseModel): + class_id: Optional[int] = Field(None) + advisor_id: Optional[int] = Field(None, ge=1) + stu_name: Optional[str] = Field(None, min_length=1, max_length=10) + native_place: Optional[str] = Field(None, min_length=1, max_length=30) + graduate_school: Optional[str] = Field(None, min_length=1, max_length=50) + education: Optional[str] = Field(None, min_length=1, max_length=10) + major: Optional[str] = Field(None, min_length=1, max_length=20) + age: Optional[int] = Field(None, ge = 18, le =40) + gender: Optional[str] = Field(None, min_length=1, max_length=20) + +# ----------响应体模型------------- +class StudentResponse(BaseModel): + stu_id: int + class_id: int # 数据库非空,这里必须是 int + stu_name: str + native_place: str + graduate_school: Optional[str] + education: str + major: Optional[str] + # 敏感字段已在此模型中脱敏 + + class Config: + from_attributes = True #支持orm对象转换,让pydantic可以读取ORM数据库对象(SQLAlchemy模型) + + + + diff --git a/sqlalchemy_fastapi_demo/scheme/teachers.py b/sqlalchemy_fastapi_demo/scheme/teachers.py new file mode 100644 index 0000000..45a5120 --- /dev/null +++ b/sqlalchemy_fastapi_demo/scheme/teachers.py @@ -0,0 +1,52 @@ +# 正确 +from pydantic import Field + +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel, field_validator + + +# --------------------请求体模型----------------------------- +# 用于增加1行数据# 加了软删除标签 +class TeacherAdd(BaseModel): + teacher_id:int=Field(...,ge=1,description='教师ID是整数类型') + class_id:int=Field(...,ge=1,description='班级ID是整数类型') + teacher_name:str=Field(...,description='教师姓名') + job_name:str=Field(...,min_length=2,description='主讲老师、班主任、助教') + is_deleted:int=Field(0,ge=0,le=0,description='只能输入0,0代表未删除,1代表已经被软删除') + + @field_validator("job_name") + @classmethod + def validate_job_name(cls, v): + """校验 job_name 必须是 主讲/班主任/助教 之一""" + allowed = ["主讲老师", "班主任", "助教"] + if v not in allowed: + raise ValueError(f"job_name 必须是 {allowed} 之一,当前值: {v}") + return v +# 用于更新数据 +class TeacherUpdate(BaseModel): + class_id: Optional[int] = Field(None, ge=1, description='班级ID是整数类型') # ge=1 只对非 None 的值生效 + teacher_name: Optional[str] = Field(None, description='教师姓名') + job_name: Optional[str] = Field(None,min_length=2, description='主讲老师、班主任、助教') + + @field_validator("job_name") + @classmethod + def validate_job_name(cls, v): + """校验 job_name 必须是 主讲/班主任/助教 之一""" + allowed = ["主讲老师", "班主任", "助教"] + if v not in allowed: + raise ValueError(f"job_name 必须是 {allowed} 之一,当前值: {v}") + return v +# --------------------- 响应模型 ---------------------------- +class TeacherResponse(BaseModel): + teacher_id: int + class_id: int + teacher_name: str + job_name: str + + class Config: # 告诉 Pydantic:"可以从任意对象的属性中读取数据,而不只是从字典中读取。" + from_attributes = True # 支持 ORM 对象转换 + + +