mirror of
https://github.com/fastapi-practices/fastapi-best-architecture.git
synced 2026-09-21 21:15:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f958fc42a | ||
|
|
e6e53296a8 | ||
|
|
f533de8abd | ||
|
|
adc6427aab | ||
|
|
d034b78b48 | ||
|
|
6deda906de | ||
|
|
a063105de8 | ||
|
|
02b4215742 | ||
|
|
56b6e2113f | ||
|
|
4fcc78eb94 | ||
|
|
b28a4d7673 | ||
|
|
27383e4ff5 | ||
|
|
bf16f8916d | ||
|
|
75a62ac6aa | ||
|
|
bbc4aaa020 | ||
|
|
89e5d02fe2 | ||
|
|
a93973af06 |
@@ -18,4 +18,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
file: CHANGELOG.md
|
file: CHANGELOG.md
|
||||||
pull_request: true
|
pull_request: true
|
||||||
|
commit_summary_template: 'Update the changelog for %s'
|
||||||
|
args: -c
|
||||||
github_token: ${{ secrets.GH_TOKEN }}
|
github_token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|||||||
+187
@@ -1,3 +1,67 @@
|
|||||||
|
<a id="v1.10.1"></a>
|
||||||
|
# [v1.10.1](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.10.1) - 2025-10-18
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
* Update the changelog for v1.10.0 by [@wu-clan](https://github.com/wu-clan) in [#864](https://github.com/fastapi-practices/fastapi_best_architecture/pull/864)
|
||||||
|
* Fix tasks related to deleting db logs by [@wu-clan](https://github.com/wu-clan) in [#863](https://github.com/fastapi-practices/fastapi_best_architecture/pull/863)
|
||||||
|
* Fix the volume in the docker compose script by [@wu-clan](https://github.com/wu-clan) in [#865](https://github.com/fastapi-practices/fastapi_best_architecture/pull/865)
|
||||||
|
* Update the release changelog workflow by [@wu-clan](https://github.com/wu-clan) in [#867](https://github.com/fastapi-practices/fastapi_best_architecture/pull/867)
|
||||||
|
* Bump dependencies to the latest version by [@wu-clan](https://github.com/wu-clan) in [#868](https://github.com/fastapi-practices/fastapi_best_architecture/pull/868)
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.10.0...v1.10.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
|
[Changes][v1.10.1]
|
||||||
|
|
||||||
|
|
||||||
|
<a id="v1.10.0"></a>
|
||||||
|
# [v1.10.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.10.0) - 2025-10-17
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
* Fix the import table cli command by [@wu-clan](https://github.com/wu-clan) in [#860](https://github.com/fastapi-practices/fastapi_best_architecture/pull/860)
|
||||||
|
* Update unique judgment logic for dict data by [@wu-clan](https://github.com/wu-clan) in [#859](https://github.com/fastapi-practices/fastapi_best_architecture/pull/859)
|
||||||
|
* Fix the api ninja in code generation by [@wu-clan](https://github.com/wu-clan) in [#858](https://github.com/fastapi-practices/fastapi_best_architecture/pull/858)
|
||||||
|
* Fix dict plugin pgsql init script missing by [@wu-clan](https://github.com/wu-clan) in [#857](https://github.com/fastapi-practices/fastapi_best_architecture/pull/857)
|
||||||
|
* Update the changelog for v1.9.0 by [@wu-clan](https://github.com/wu-clan) in [#856](https://github.com/fastapi-practices/fastapi_best_architecture/pull/856)
|
||||||
|
* Fix ctx in validation exception handler by [@wu-clan](https://github.com/wu-clan) in [#861](https://github.com/fastapi-practices/fastapi_best_architecture/pull/861)
|
||||||
|
* Update the primary database to postgresql by [@wu-clan](https://github.com/wu-clan) in [#829](https://github.com/fastapi-practices/fastapi_best_architecture/pull/829)
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.9.0...v1.10.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
|
[Changes][v1.10.0]
|
||||||
|
|
||||||
|
|
||||||
|
<a id="v1.9.0"></a>
|
||||||
|
# [v1.9.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.9.0) - 2025-10-16
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
* Update changelog for v1.8.3 by [@wu-clan](https://github.com/wu-clan) in [#849](https://github.com/fastapi-practices/fastapi_best_architecture/pull/849)
|
||||||
|
* Bump fastapi and pydantic to the latest by [@wu-clan](https://github.com/wu-clan) in [#851](https://github.com/fastapi-practices/fastapi_best_architecture/pull/851)
|
||||||
|
* Update superuser verify to dependency injection by [@wu-clan](https://github.com/wu-clan) in [#852](https://github.com/fastapi-practices/fastapi_best_architecture/pull/852)
|
||||||
|
* Fix the superuser verify missing auth by [@wu-clan](https://github.com/wu-clan) in [#854](https://github.com/fastapi-practices/fastapi_best_architecture/pull/854)
|
||||||
|
* Update request state usage to context variable by [@wu-clan](https://github.com/wu-clan) in [#853](https://github.com/fastapi-practices/fastapi_best_architecture/pull/853)
|
||||||
|
* Fix safely of access ctx in exception handlers by [@wu-clan](https://github.com/wu-clan) in [#855](https://github.com/fastapi-practices/fastapi_best_architecture/pull/855)
|
||||||
|
* Refactor the service layer db session call method by [@wu-clan](https://github.com/wu-clan) in [#850](https://github.com/fastapi-practices/fastapi_best_architecture/pull/850)
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.3...v1.9.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
|
[Changes][v1.9.0]
|
||||||
|
|
||||||
|
|
||||||
<a id="v1.8.3"></a>
|
<a id="v1.8.3"></a>
|
||||||
# [v1.8.3](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.8.3) - 2025-10-13
|
# [v1.8.3](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.8.3) - 2025-10-13
|
||||||
|
|
||||||
@@ -13,6 +77,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.2...v1.8.3
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.2...v1.8.3
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.8.3]
|
[Changes][v1.8.3]
|
||||||
|
|
||||||
|
|
||||||
@@ -48,6 +116,12 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.1...v1.8.2
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.1...v1.8.2
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/MortyZhaoy"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FMortyZhaoy.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@MortyZhaoy"></a>
|
||||||
|
<a href="https://github.com/byte-voyager"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fbyte-voyager.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@byte-voyager"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.8.2]
|
[Changes][v1.8.2]
|
||||||
|
|
||||||
|
|
||||||
@@ -92,6 +166,15 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.0...v1.8.1
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.0...v1.8.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/IAseven"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FIAseven.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@IAseven"></a>
|
||||||
|
<a href="https://github.com/siyue-wang"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fsiyue-wang.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@siyue-wang"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
<a href="https://github.com/wuyao4"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwuyao4.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wuyao4"></a>
|
||||||
|
<a href="https://github.com/yanlingsishao"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fyanlingsishao.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@yanlingsishao"></a>
|
||||||
|
<a href="https://github.com/yzbf-lin"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fyzbf-lin.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@yzbf-lin"></a>
|
||||||
|
|
||||||
[Changes][v1.8.1]
|
[Changes][v1.8.1]
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +219,12 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.7.0...v1.8.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.7.0...v1.8.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/IAseven"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FIAseven.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@IAseven"></a>
|
||||||
|
<a href="https://github.com/downdawn"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdowndawn.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@downdawn"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.8.0]
|
[Changes][v1.8.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -171,6 +260,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.6.0...v1.7.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.6.0...v1.7.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.7.0]
|
[Changes][v1.7.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -194,6 +287,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.2...v1.6.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.2...v1.6.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.6.0]
|
[Changes][v1.6.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -220,6 +317,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.1...v1.5.2
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.1...v1.5.2
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/downdawn"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdowndawn.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@downdawn"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.5.2]
|
[Changes][v1.5.2]
|
||||||
|
|
||||||
|
|
||||||
@@ -236,6 +338,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.0...v1.5.1
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.5.0...v1.5.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/downdawn"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdowndawn.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@downdawn"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.5.1]
|
[Changes][v1.5.1]
|
||||||
|
|
||||||
|
|
||||||
@@ -259,6 +366,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.3...v1.5.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.3...v1.5.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.5.0]
|
[Changes][v1.5.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -280,6 +391,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.2...v1.4.3
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.2...v1.4.3
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.4.3]
|
[Changes][v1.4.3]
|
||||||
|
|
||||||
|
|
||||||
@@ -301,6 +416,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.1...v1.4.2
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.1...v1.4.2
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/huyuwei1996"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fhuyuwei1996.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@huyuwei1996"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.4.2]
|
[Changes][v1.4.2]
|
||||||
|
|
||||||
|
|
||||||
@@ -318,6 +438,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.0...v1.4.1
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.0...v1.4.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.4.1]
|
[Changes][v1.4.1]
|
||||||
|
|
||||||
|
|
||||||
@@ -339,6 +463,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.3.0...v1.4.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.3.0...v1.4.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.4.0]
|
[Changes][v1.4.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -356,6 +484,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.2.0...v1.3.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.2.0...v1.3.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.3.0]
|
[Changes][v1.3.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -373,6 +505,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.2...v1.2.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.2...v1.2.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.2.0]
|
[Changes][v1.2.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -390,6 +526,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.1...v1.1.2
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.1...v1.1.2
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.1.2]
|
[Changes][v1.1.2]
|
||||||
|
|
||||||
|
|
||||||
@@ -404,6 +544,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.0...v1.1.1
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.0...v1.1.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.1.1]
|
[Changes][v1.1.1]
|
||||||
|
|
||||||
|
|
||||||
@@ -423,6 +567,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.5...v1.1.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.5...v1.1.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/huyuwei1996"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fhuyuwei1996.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@huyuwei1996"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.1.0]
|
[Changes][v1.1.0]
|
||||||
|
|
||||||
|
|
||||||
@@ -447,6 +596,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.4...v1.0.5
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.4...v1.0.5
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.0.5]
|
[Changes][v1.0.5]
|
||||||
|
|
||||||
|
|
||||||
@@ -475,6 +628,12 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.3...v1.0.4
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.3...v1.0.4
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/PoetryL"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FPoetryL.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@PoetryL"></a>
|
||||||
|
<a href="https://github.com/ThankCat"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FThankCat.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@ThankCat"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.0.4]
|
[Changes][v1.0.4]
|
||||||
|
|
||||||
|
|
||||||
@@ -493,6 +652,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.2...v1.0.3
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.2...v1.0.3
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/huyuwei1996"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fhuyuwei1996.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@huyuwei1996"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.0.3]
|
[Changes][v1.0.3]
|
||||||
|
|
||||||
|
|
||||||
@@ -508,6 +672,10 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.1...v1.0.2
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.1...v1.0.2
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.0.2]
|
[Changes][v1.0.2]
|
||||||
|
|
||||||
|
|
||||||
@@ -527,6 +695,11 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.0...v1.0.1
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.0.0...v1.0.1
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/huyuwei1996"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fhuyuwei1996.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@huyuwei1996"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
|
||||||
[Changes][v1.0.1]
|
[Changes][v1.0.1]
|
||||||
|
|
||||||
|
|
||||||
@@ -852,9 +1025,23 @@
|
|||||||
|
|
||||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/commits/v1.0.0
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/commits/v1.0.0
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/Meepoljdx"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2FMeepoljdx.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@Meepoljdx"></a>
|
||||||
|
<a href="https://github.com/dependabot"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdependabot.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@dependabot"></a>
|
||||||
|
<a href="https://github.com/dividduang"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdividduang.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@dividduang"></a>
|
||||||
|
<a href="https://github.com/downdawn"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fdowndawn.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@downdawn"></a>
|
||||||
|
<a href="https://github.com/obrua"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fobrua.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@obrua"></a>
|
||||||
|
<a href="https://github.com/qhp13654398483"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fqhp13654398483.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@qhp13654398483"></a>
|
||||||
|
<a href="https://github.com/wu-clan"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fwu-clan.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@wu-clan"></a>
|
||||||
|
<a href="https://github.com/yshan2028"><img src="https://wsrv.nl/?url=https%3A%2F%2Fgithub.com%2Fyshan2028.png&w=128&h=128&fit=cover&mask=circle" width="64" height="64" alt="@yshan2028"></a>
|
||||||
|
|
||||||
[Changes][v1.0.0]
|
[Changes][v1.0.0]
|
||||||
|
|
||||||
|
|
||||||
|
[v1.10.1]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.10.0...v1.10.1
|
||||||
|
[v1.10.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.9.0...v1.10.0
|
||||||
|
[v1.9.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.3...v1.9.0
|
||||||
[v1.8.3]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.2...v1.8.3
|
[v1.8.3]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.2...v1.8.3
|
||||||
[v1.8.2]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.1...v1.8.2
|
[v1.8.2]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.1...v1.8.2
|
||||||
[v1.8.1]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.0...v1.8.1
|
[v1.8.1]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.8.0...v1.8.1
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Env
|
# Env
|
||||||
ENVIRONMENT='dev'
|
ENVIRONMENT='dev'
|
||||||
# Database
|
# Database
|
||||||
DATABASE_TYPE='mysql'
|
DATABASE_TYPE='postgresql'
|
||||||
DATABASE_HOST='127.0.0.1'
|
DATABASE_HOST='127.0.0.1'
|
||||||
DATABASE_PORT=3306
|
DATABASE_PORT=5432
|
||||||
DATABASE_USER='root'
|
DATABASE_USER='postgres'
|
||||||
DATABASE_PASSWORD='123456'
|
DATABASE_PASSWORD='123456'
|
||||||
# Redis
|
# Redis
|
||||||
REDIS_HOST='127.0.0.1'
|
REDIS_HOST='127.0.0.1'
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
from backend.common.i18n import i18n
|
from backend.common.i18n import i18n
|
||||||
|
|
||||||
__version__ = '1.8.2'
|
__version__ = '1.10.2'
|
||||||
|
|
||||||
|
|
||||||
# 初始化 i18n
|
# 初始化 i18n
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ def get_app_models() -> list[type]:
|
|||||||
apps = [d for d in list_dirs if os.path.isdir(os.path.join(app_path, d)) and d != '__pycache__']
|
apps = [d for d in list_dirs if os.path.isdir(os.path.join(app_path, d)) and d != '__pycache__']
|
||||||
|
|
||||||
objs = []
|
objs = []
|
||||||
|
|
||||||
for app in apps:
|
for app in apps:
|
||||||
module_path = f'backend.app.{app}.model'
|
module_path = f'backend.app.{app}.model'
|
||||||
obj = get_model_objects(module_path)
|
obj = get_model_objects(module_path)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class CRUDDept(CRUDPlus[Dept]):
|
|||||||
:param dept_id: 部门 ID
|
:param dept_id: 部门 ID
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return await self.select_model_by_column(db, id=dept_id, del_flag=0)
|
return await self.select_model_by_column(db, id=dept_id, del_flag=False)
|
||||||
|
|
||||||
async def get_by_name(self, db: AsyncSession, name: str) -> Dept | None:
|
async def get_by_name(self, db: AsyncSession, name: str) -> Dept | None:
|
||||||
"""
|
"""
|
||||||
@@ -30,7 +30,7 @@ class CRUDDept(CRUDPlus[Dept]):
|
|||||||
:param name: 部门名称
|
:param name: 部门名称
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return await self.select_model_by_column(db, name=name, del_flag=0)
|
return await self.select_model_by_column(db, name=name, del_flag=False)
|
||||||
|
|
||||||
async def get_all(
|
async def get_all(
|
||||||
self,
|
self,
|
||||||
@@ -52,7 +52,7 @@ class CRUDDept(CRUDPlus[Dept]):
|
|||||||
:param status: 部门状态
|
:param status: 部门状态
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
filters = {'del_flag': 0}
|
filters = {'del_flag': False}
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
filters['name__like'] = f'%{name}%'
|
filters['name__like'] = f'%{name}%'
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.app.admin.model.m2m import sys_data_scope_rule
|
from backend.app.admin.model.m2m import sys_data_scope_rule
|
||||||
@@ -18,14 +19,14 @@ class DataRule(Base):
|
|||||||
__tablename__ = 'sys_data_rule'
|
__tablename__ = 'sys_data_rule'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(500), unique=True, comment='名称')
|
name: Mapped[str] = mapped_column(sa.String(500), unique=True, comment='名称')
|
||||||
model: Mapped[str] = mapped_column(String(50), comment='SQLA 模型名,对应 DATA_PERMISSION_MODELS 键名')
|
model: Mapped[str] = mapped_column(sa.String(50), comment='SQLA 模型名,对应 DATA_PERMISSION_MODELS 键名')
|
||||||
column: Mapped[str] = mapped_column(String(20), comment='模型字段名')
|
column: Mapped[str] = mapped_column(sa.String(20), comment='模型字段名')
|
||||||
operator: Mapped[int] = mapped_column(comment='运算符(0:and、1:or)')
|
operator: Mapped[int] = mapped_column(comment='运算符(0:and、1:or)')
|
||||||
expression: Mapped[int] = mapped_column(
|
expression: Mapped[int] = mapped_column(
|
||||||
comment='表达式(0:==、1:!=、2:>、3:>=、4:<、5:<=、6:in、7:not_in)',
|
comment='表达式(0:==、1:!=、2:>、3:>=、4:<、5:<=、6:in、7:not_in)',
|
||||||
)
|
)
|
||||||
value: Mapped[str] = mapped_column(String(255), comment='规则值')
|
value: Mapped[str] = mapped_column(sa.String(255), comment='规则值')
|
||||||
|
|
||||||
# 数据范围规则多对多
|
# 数据范围规则多对多
|
||||||
scopes: Mapped[list[DataScope]] = relationship(init=False, secondary=sys_data_scope_rule, back_populates='rules')
|
scopes: Mapped[list[DataScope]] = relationship(init=False, secondary=sys_data_scope_rule, back_populates='rules')
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.app.admin.model.m2m import sys_data_scope_rule, sys_role_data_scope
|
from backend.app.admin.model.m2m import sys_data_scope_rule, sys_role_data_scope
|
||||||
@@ -18,7 +19,7 @@ class DataScope(Base):
|
|||||||
__tablename__ = 'sys_data_scope'
|
__tablename__ = 'sys_data_scope'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(50), unique=True, comment='名称')
|
name: Mapped[str] = mapped_column(sa.String(50), unique=True, comment='名称')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='状态(0停用 1正常)')
|
||||||
|
|
||||||
# 数据范围规则多对多
|
# 数据范围规则多对多
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, Boolean, ForeignKey, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.postgresql import INTEGER
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, id_key
|
||||||
@@ -18,25 +18,17 @@ class Dept(Base):
|
|||||||
__tablename__ = 'sys_dept'
|
__tablename__ = 'sys_dept'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(50), comment='部门名称')
|
name: Mapped[str] = mapped_column(sa.String(50), comment='部门名称')
|
||||||
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
||||||
leader: Mapped[str | None] = mapped_column(String(20), default=None, comment='负责人')
|
leader: Mapped[str | None] = mapped_column(sa.String(20), default=None, comment='负责人')
|
||||||
phone: Mapped[str | None] = mapped_column(String(11), default=None, comment='手机')
|
phone: Mapped[str | None] = mapped_column(sa.String(11), default=None, comment='手机')
|
||||||
email: Mapped[str | None] = mapped_column(String(50), default=None, comment='邮箱')
|
email: Mapped[str | None] = mapped_column(sa.String(50), default=None, comment='邮箱')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='部门状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='部门状态(0停用 1正常)')
|
||||||
del_flag: Mapped[bool] = mapped_column(
|
del_flag: Mapped[bool] = mapped_column(default=False, comment='删除标志(0删除 1存在)')
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
|
||||||
default=False,
|
|
||||||
comment='删除标志(0删除 1存在)',
|
|
||||||
)
|
|
||||||
|
|
||||||
# 父级部门一对多
|
# 父级部门一对多
|
||||||
parent_id: Mapped[int | None] = mapped_column(
|
parent_id: Mapped[int | None] = mapped_column(
|
||||||
BigInteger,
|
sa.BigInteger, sa.ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, index=True, comment='父部门ID'
|
||||||
ForeignKey('sys_dept.id', ondelete='SET NULL'),
|
|
||||||
default=None,
|
|
||||||
index=True,
|
|
||||||
comment='父部门ID',
|
|
||||||
)
|
)
|
||||||
parent: Mapped[Dept | None] = relationship(init=False, back_populates='children', remote_side=[id])
|
parent: Mapped[Dept | None] = relationship(init=False, back_populates='children', remote_side=[id])
|
||||||
children: Mapped[list[Dept] | None] = relationship(init=False, back_populates='parent')
|
children: Mapped[list[Dept] | None] = relationship(init=False, back_populates='parent')
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from backend.common.model import DataClassBase, TimeZone, id_key
|
from backend.common.model import DataClassBase, TimeZone, UniversalText, id_key
|
||||||
from backend.utils.timezone import timezone
|
from backend.utils.timezone import timezone
|
||||||
|
|
||||||
|
|
||||||
@@ -15,18 +14,18 @@ class LoginLog(DataClassBase):
|
|||||||
__tablename__ = 'sys_login_log'
|
__tablename__ = 'sys_login_log'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
user_uuid: Mapped[str] = mapped_column(String(50), comment='用户UUID')
|
user_uuid: Mapped[str] = mapped_column(sa.String(50), comment='用户UUID')
|
||||||
username: Mapped[str] = mapped_column(String(20), comment='用户名')
|
username: Mapped[str] = mapped_column(sa.String(20), comment='用户名')
|
||||||
status: Mapped[int] = mapped_column(insert_default=0, comment='登录状态(0失败 1成功)')
|
status: Mapped[int] = mapped_column(insert_default=0, comment='登录状态(0失败 1成功)')
|
||||||
ip: Mapped[str] = mapped_column(String(50), comment='登录IP地址')
|
ip: Mapped[str] = mapped_column(sa.String(50), comment='登录IP地址')
|
||||||
country: Mapped[str | None] = mapped_column(String(50), comment='国家')
|
country: Mapped[str | None] = mapped_column(sa.String(50), comment='国家')
|
||||||
region: Mapped[str | None] = mapped_column(String(50), comment='地区')
|
region: Mapped[str | None] = mapped_column(sa.String(50), comment='地区')
|
||||||
city: Mapped[str | None] = mapped_column(String(50), comment='城市')
|
city: Mapped[str | None] = mapped_column(sa.String(50), comment='城市')
|
||||||
user_agent: Mapped[str] = mapped_column(String(255), comment='请求头')
|
user_agent: Mapped[str] = mapped_column(sa.String(255), comment='请求头')
|
||||||
os: Mapped[str | None] = mapped_column(String(50), comment='操作系统')
|
os: Mapped[str | None] = mapped_column(sa.String(50), comment='操作系统')
|
||||||
browser: Mapped[str | None] = mapped_column(String(50), comment='浏览器')
|
browser: Mapped[str | None] = mapped_column(sa.String(50), comment='浏览器')
|
||||||
device: Mapped[str | None] = mapped_column(String(50), comment='设备')
|
device: Mapped[str | None] = mapped_column(sa.String(50), comment='设备')
|
||||||
msg: Mapped[str] = mapped_column(LONGTEXT().with_variant(TEXT, 'postgresql'), comment='提示消息')
|
msg: Mapped[str] = mapped_column(UniversalText, comment='提示消息')
|
||||||
login_time: Mapped[datetime] = mapped_column(TimeZone, comment='登录时间')
|
login_time: Mapped[datetime] = mapped_column(TimeZone, comment='登录时间')
|
||||||
created_time: Mapped[datetime] = mapped_column(
|
created_time: Mapped[datetime] = mapped_column(
|
||||||
TimeZone,
|
TimeZone,
|
||||||
|
|||||||
@@ -1,52 +1,62 @@
|
|||||||
from sqlalchemy import BigInteger, Column, ForeignKey, Table
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from backend.common.model import MappedBase
|
from backend.common.model import MappedBase
|
||||||
|
|
||||||
sys_user_role = Table(
|
sys_user_role = sa.Table(
|
||||||
'sys_user_role',
|
'sys_user_role',
|
||||||
MappedBase.metadata,
|
MappedBase.metadata,
|
||||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
sa.Column('id', sa.BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||||
Column('user_id', BigInteger, ForeignKey('sys_user.id', ondelete='CASCADE'), primary_key=True, comment='用户ID'),
|
sa.Column(
|
||||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
'user_id', sa.BigInteger, sa.ForeignKey('sys_user.id', ondelete='CASCADE'), primary_key=True, comment='用户ID'
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
|
'role_id', sa.BigInteger, sa.ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
sys_role_menu = Table(
|
sys_role_menu = sa.Table(
|
||||||
'sys_role_menu',
|
'sys_role_menu',
|
||||||
MappedBase.metadata,
|
MappedBase.metadata,
|
||||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
sa.Column('id', sa.BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
sa.Column(
|
||||||
Column('menu_id', BigInteger, ForeignKey('sys_menu.id', ondelete='CASCADE'), primary_key=True, comment='菜单ID'),
|
'role_id', sa.BigInteger, sa.ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
|
'menu_id', sa.BigInteger, sa.ForeignKey('sys_menu.id', ondelete='CASCADE'), primary_key=True, comment='菜单ID'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
sys_role_data_scope = Table(
|
sys_role_data_scope = sa.Table(
|
||||||
'sys_role_data_scope',
|
'sys_role_data_scope',
|
||||||
MappedBase.metadata,
|
MappedBase.metadata,
|
||||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键 ID'),
|
sa.Column('id', sa.BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键 ID'),
|
||||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色 ID'),
|
sa.Column(
|
||||||
Column(
|
'role_id', sa.BigInteger, sa.ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色 ID'
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
'data_scope_id',
|
'data_scope_id',
|
||||||
BigInteger,
|
sa.BigInteger,
|
||||||
ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
sa.ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
comment='数据范围 ID',
|
comment='数据范围 ID',
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
sys_data_scope_rule = Table(
|
sys_data_scope_rule = sa.Table(
|
||||||
'sys_data_scope_rule',
|
'sys_data_scope_rule',
|
||||||
MappedBase.metadata,
|
MappedBase.metadata,
|
||||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
sa.Column('id', sa.BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||||
Column(
|
sa.Column(
|
||||||
'data_scope_id',
|
'data_scope_id',
|
||||||
BigInteger,
|
sa.BigInteger,
|
||||||
ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
sa.ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
comment='数据范围 ID',
|
comment='数据范围 ID',
|
||||||
),
|
),
|
||||||
Column(
|
sa.Column(
|
||||||
'data_rule_id',
|
'data_rule_id',
|
||||||
BigInteger,
|
sa.BigInteger,
|
||||||
ForeignKey('sys_data_rule.id', ondelete='CASCADE'),
|
sa.ForeignKey('sys_data_rule.id', ondelete='CASCADE'),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
comment='数据规则 ID',
|
comment='数据规则 ID',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, ForeignKey, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.app.admin.model.m2m import sys_role_menu
|
from backend.app.admin.model.m2m import sys_role_menu
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.app.admin.model import Role
|
from backend.app.admin.model import Role
|
||||||
@@ -20,35 +19,23 @@ class Menu(Base):
|
|||||||
__tablename__ = 'sys_menu'
|
__tablename__ = 'sys_menu'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
title: Mapped[str] = mapped_column(String(50), comment='菜单标题')
|
title: Mapped[str] = mapped_column(sa.String(50), comment='菜单标题')
|
||||||
name: Mapped[str] = mapped_column(String(50), comment='菜单名称')
|
name: Mapped[str] = mapped_column(sa.String(50), comment='菜单名称')
|
||||||
path: Mapped[str | None] = mapped_column(String(200), comment='路由地址')
|
path: Mapped[str | None] = mapped_column(sa.String(200), comment='路由地址')
|
||||||
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
||||||
icon: Mapped[str | None] = mapped_column(String(100), default=None, comment='菜单图标')
|
icon: Mapped[str | None] = mapped_column(sa.String(100), default=None, comment='菜单图标')
|
||||||
type: Mapped[int] = mapped_column(default=0, comment='菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)')
|
type: Mapped[int] = mapped_column(default=0, comment='菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)')
|
||||||
component: Mapped[str | None] = mapped_column(String(255), default=None, comment='组件路径')
|
component: Mapped[str | None] = mapped_column(sa.String(255), default=None, comment='组件路径')
|
||||||
perms: Mapped[str | None] = mapped_column(String(100), default=None, comment='权限标识')
|
perms: Mapped[str | None] = mapped_column(sa.String(100), default=None, comment='权限标识')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='菜单状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='菜单状态(0停用 1正常)')
|
||||||
display: Mapped[int] = mapped_column(default=1, comment='是否显示(0否 1是)')
|
display: Mapped[int] = mapped_column(default=1, comment='是否显示(0否 1是)')
|
||||||
cache: Mapped[int] = mapped_column(default=1, comment='是否缓存(0否 1是)')
|
cache: Mapped[int] = mapped_column(default=1, comment='是否缓存(0否 1是)')
|
||||||
link: Mapped[str | None] = mapped_column(
|
link: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='外链地址')
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
default=None,
|
|
||||||
comment='外链地址',
|
|
||||||
)
|
|
||||||
remark: Mapped[str | None] = mapped_column(
|
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|
||||||
# 父级菜单一对多
|
# 父级菜单一对多
|
||||||
parent_id: Mapped[int | None] = mapped_column(
|
parent_id: Mapped[int | None] = mapped_column(
|
||||||
BigInteger,
|
sa.BigInteger, sa.ForeignKey('sys_menu.id', ondelete='SET NULL'), default=None, index=True, comment='父菜单ID'
|
||||||
ForeignKey('sys_menu.id', ondelete='SET NULL'),
|
|
||||||
default=None,
|
|
||||||
index=True,
|
|
||||||
comment='父菜单ID',
|
|
||||||
)
|
)
|
||||||
parent: Mapped[Menu | None] = relationship(init=False, back_populates='children', remote_side=[id])
|
parent: Mapped[Menu | None] = relationship(init=False, back_populates='children', remote_side=[id])
|
||||||
children: Mapped[list[Menu] | None] = relationship(init=False, back_populates='parent')
|
children: Mapped[list[Menu] | None] = relationship(init=False, back_populates='parent')
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import JSON, LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from backend.common.model import DataClassBase, TimeZone, id_key
|
from backend.common.model import DataClassBase, TimeZone, UniversalText, id_key
|
||||||
from backend.utils.timezone import timezone
|
from backend.utils.timezone import timezone
|
||||||
|
|
||||||
|
|
||||||
@@ -15,28 +14,25 @@ class OperaLog(DataClassBase):
|
|||||||
__tablename__ = 'sys_opera_log'
|
__tablename__ = 'sys_opera_log'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
trace_id: Mapped[str] = mapped_column(String(32), comment='请求跟踪 ID')
|
trace_id: Mapped[str] = mapped_column(sa.String(32), comment='请求跟踪 ID')
|
||||||
username: Mapped[str | None] = mapped_column(String(20), comment='用户名')
|
username: Mapped[str | None] = mapped_column(sa.String(20), comment='用户名')
|
||||||
method: Mapped[str] = mapped_column(String(20), comment='请求类型')
|
method: Mapped[str] = mapped_column(sa.String(20), comment='请求类型')
|
||||||
title: Mapped[str] = mapped_column(String(255), comment='操作模块')
|
title: Mapped[str] = mapped_column(sa.String(255), comment='操作模块')
|
||||||
path: Mapped[str] = mapped_column(String(500), comment='请求路径')
|
path: Mapped[str] = mapped_column(sa.String(500), comment='请求路径')
|
||||||
ip: Mapped[str] = mapped_column(String(50), comment='IP地址')
|
ip: Mapped[str] = mapped_column(sa.String(50), comment='IP地址')
|
||||||
country: Mapped[str | None] = mapped_column(String(50), comment='国家')
|
country: Mapped[str | None] = mapped_column(sa.String(50), comment='国家')
|
||||||
region: Mapped[str | None] = mapped_column(String(50), comment='地区')
|
region: Mapped[str | None] = mapped_column(sa.String(50), comment='地区')
|
||||||
city: Mapped[str | None] = mapped_column(String(50), comment='城市')
|
city: Mapped[str | None] = mapped_column(sa.String(50), comment='城市')
|
||||||
user_agent: Mapped[str] = mapped_column(LONGTEXT().with_variant(TEXT, 'postgresql'), comment='请求头')
|
user_agent: Mapped[str] = mapped_column(sa.String(255), comment='请求头')
|
||||||
os: Mapped[str | None] = mapped_column(String(50), comment='操作系统')
|
os: Mapped[str | None] = mapped_column(sa.String(50), comment='操作系统')
|
||||||
browser: Mapped[str | None] = mapped_column(String(50), comment='浏览器')
|
browser: Mapped[str | None] = mapped_column(sa.String(50), comment='浏览器')
|
||||||
device: Mapped[str | None] = mapped_column(String(50), comment='设备')
|
device: Mapped[str | None] = mapped_column(sa.String(50), comment='设备')
|
||||||
args: Mapped[str | None] = mapped_column(JSON(), comment='请求参数')
|
args: Mapped[str | None] = mapped_column(sa.JSON(), comment='请求参数')
|
||||||
status: Mapped[int] = mapped_column(comment='操作状态(0异常 1正常)')
|
status: Mapped[int] = mapped_column(comment='操作状态(0异常 1正常)')
|
||||||
code: Mapped[str] = mapped_column(String(20), insert_default='200', comment='操作状态码')
|
code: Mapped[str] = mapped_column(sa.String(20), insert_default='200', comment='操作状态码')
|
||||||
msg: Mapped[str | None] = mapped_column(LONGTEXT().with_variant(TEXT, 'postgresql'), comment='提示消息')
|
msg: Mapped[str | None] = mapped_column(UniversalText, comment='提示消息')
|
||||||
cost_time: Mapped[float] = mapped_column(insert_default=0.0, comment='请求耗时(ms)')
|
cost_time: Mapped[float] = mapped_column(insert_default=0.0, comment='请求耗时(ms)')
|
||||||
opera_time: Mapped[datetime] = mapped_column(TimeZone, comment='操作时间')
|
opera_time: Mapped[datetime] = mapped_column(TimeZone, comment='操作时间')
|
||||||
created_time: Mapped[datetime] = mapped_column(
|
created_time: Mapped[datetime] = mapped_column(
|
||||||
TimeZone,
|
TimeZone, init=False, default_factory=timezone.now, comment='创建时间'
|
||||||
init=False,
|
|
||||||
default_factory=timezone.now,
|
|
||||||
comment='创建时间',
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import Boolean, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import INTEGER, TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.app.admin.model.m2m import sys_role_data_scope, sys_role_menu, sys_user_role
|
from backend.app.admin.model.m2m import sys_role_data_scope, sys_role_menu, sys_user_role
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.app.admin.model import DataScope, Menu, User
|
from backend.app.admin.model import DataScope, Menu, User
|
||||||
@@ -20,18 +19,10 @@ class Role(Base):
|
|||||||
__tablename__ = 'sys_role'
|
__tablename__ = 'sys_role'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(20), unique=True, comment='角色名称')
|
name: Mapped[str] = mapped_column(sa.String(20), unique=True, comment='角色名称')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='角色状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='角色状态(0停用 1正常)')
|
||||||
is_filter_scopes: Mapped[bool] = mapped_column(
|
is_filter_scopes: Mapped[bool] = mapped_column(default=True, comment='过滤数据权限(0否 1是)')
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
default=True,
|
|
||||||
comment='过滤数据权限(0否 1是)',
|
|
||||||
)
|
|
||||||
remark: Mapped[str | None] = mapped_column(
|
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|
||||||
# 角色用户多对多
|
# 角色用户多对多
|
||||||
users: Mapped[list[User]] = relationship(init=False, secondary=sys_user_role, back_populates='roles')
|
users: Mapped[list[User]] = relationship(init=False, secondary=sys_user_role, back_populates='roles')
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import VARBINARY, Boolean, ForeignKey, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.postgresql import BYTEA, INTEGER
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.app.admin.model.m2m import sys_user_role
|
from backend.app.admin.model.m2m import sys_user_role
|
||||||
@@ -22,43 +22,26 @@ class User(Base):
|
|||||||
__tablename__ = 'sys_user'
|
__tablename__ = 'sys_user'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
uuid: Mapped[str] = mapped_column(String(50), init=False, default_factory=uuid4_str, unique=True)
|
uuid: Mapped[str] = mapped_column(sa.String(50), init=False, default_factory=uuid4_str, unique=True)
|
||||||
username: Mapped[str] = mapped_column(String(20), unique=True, index=True, comment='用户名')
|
username: Mapped[str] = mapped_column(sa.String(20), unique=True, index=True, comment='用户名')
|
||||||
nickname: Mapped[str] = mapped_column(String(20), comment='昵称')
|
nickname: Mapped[str] = mapped_column(sa.String(20), comment='昵称')
|
||||||
password: Mapped[str | None] = mapped_column(String(255), comment='密码')
|
password: Mapped[str | None] = mapped_column(sa.String(255), comment='密码')
|
||||||
salt: Mapped[bytes | None] = mapped_column(VARBINARY(255).with_variant(BYTEA(255), 'postgresql'), comment='加密盐')
|
salt: Mapped[bytes | None] = mapped_column(sa.LargeBinary(255), comment='加密盐')
|
||||||
email: Mapped[str | None] = mapped_column(String(50), default=None, unique=True, index=True, comment='邮箱')
|
email: Mapped[str | None] = mapped_column(sa.String(50), default=None, unique=True, index=True, comment='邮箱')
|
||||||
phone: Mapped[str | None] = mapped_column(String(11), default=None, comment='手机号')
|
phone: Mapped[str | None] = mapped_column(sa.String(11), default=None, comment='手机号')
|
||||||
avatar: Mapped[str | None] = mapped_column(String(255), default=None, comment='头像')
|
avatar: Mapped[str | None] = mapped_column(sa.String(255), default=None, comment='头像')
|
||||||
status: Mapped[int] = mapped_column(default=1, index=True, comment='用户账号状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, index=True, comment='用户账号状态(0停用 1正常)')
|
||||||
is_superuser: Mapped[bool] = mapped_column(
|
is_superuser: Mapped[bool] = mapped_column(default=False, comment='超级权限(0否 1是)')
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
is_staff: Mapped[bool] = mapped_column(default=False, comment='后台管理登陆(0否 1是)')
|
||||||
default=False,
|
is_multi_login: Mapped[bool] = mapped_column(default=False, comment='是否重复登陆(0否 1是)')
|
||||||
comment='超级权限(0否 1是)',
|
|
||||||
)
|
|
||||||
is_staff: Mapped[bool] = mapped_column(
|
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
|
||||||
default=False,
|
|
||||||
comment='后台管理登陆(0否 1是)',
|
|
||||||
)
|
|
||||||
is_multi_login: Mapped[bool] = mapped_column(
|
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
|
||||||
default=False,
|
|
||||||
comment='是否重复登陆(0否 1是)',
|
|
||||||
)
|
|
||||||
join_time: Mapped[datetime] = mapped_column(TimeZone, init=False, default_factory=timezone.now, comment='注册时间')
|
join_time: Mapped[datetime] = mapped_column(TimeZone, init=False, default_factory=timezone.now, comment='注册时间')
|
||||||
last_login_time: Mapped[datetime | None] = mapped_column(
|
last_login_time: Mapped[datetime | None] = mapped_column(
|
||||||
TimeZone,
|
TimeZone, init=False, onupdate=timezone.now, comment='上次登录'
|
||||||
init=False,
|
|
||||||
onupdate=timezone.now,
|
|
||||||
comment='上次登录',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 部门用户一对多
|
# 部门用户一对多
|
||||||
dept_id: Mapped[int | None] = mapped_column(
|
dept_id: Mapped[int | None] = mapped_column(
|
||||||
ForeignKey('sys_dept.id', ondelete='SET NULL'),
|
sa.BigInteger, sa.ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, comment='部门关联ID'
|
||||||
default=None,
|
|
||||||
comment='部门关联ID',
|
|
||||||
)
|
)
|
||||||
dept: Mapped[Dept | None] = relationship(init=False, back_populates='users')
|
dept: Mapped[Dept | None] = relationship(init=False, back_populates='users')
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,13 @@ import asyncio
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import (
|
import sqlalchemy as sa
|
||||||
JSON,
|
|
||||||
Boolean,
|
from sqlalchemy import event
|
||||||
String,
|
|
||||||
event,
|
|
||||||
)
|
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import INTEGER, TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from backend.common.exception import errors
|
from backend.common.exception import errors
|
||||||
from backend.common.model import Base, TimeZone, id_key
|
from backend.common.model import Base, TimeZone, UniversalText, id_key
|
||||||
from backend.core.conf import settings
|
from backend.core.conf import settings
|
||||||
from backend.database.redis import redis_client
|
from backend.database.redis import redis_client
|
||||||
from backend.utils.timezone import timezone
|
from backend.utils.timezone import timezone
|
||||||
@@ -25,37 +20,25 @@ class TaskScheduler(Base):
|
|||||||
__tablename__ = 'task_scheduler'
|
__tablename__ = 'task_scheduler'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(50), unique=True, comment='任务名称')
|
name: Mapped[str] = mapped_column(sa.String(50), unique=True, comment='任务名称')
|
||||||
task: Mapped[str] = mapped_column(String(255), comment='要运行的 Celery 任务')
|
task: Mapped[str] = mapped_column(sa.String(255), comment='要运行的 Celery 任务')
|
||||||
args: Mapped[str | None] = mapped_column(JSON(), comment='任务可接收的位置参数')
|
args: Mapped[str | None] = mapped_column(sa.JSON(), comment='任务可接收的位置参数')
|
||||||
kwargs: Mapped[str | None] = mapped_column(JSON(), comment='任务可接收的关键字参数')
|
kwargs: Mapped[str | None] = mapped_column(sa.JSON(), comment='任务可接收的关键字参数')
|
||||||
queue: Mapped[str | None] = mapped_column(String(255), comment='CELERY_TASK_QUEUES 中定义的队列')
|
queue: Mapped[str | None] = mapped_column(sa.String(255), comment='CELERY_TASK_QUEUES 中定义的队列')
|
||||||
exchange: Mapped[str | None] = mapped_column(String(255), comment='低级别 AMQP 路由的交换机')
|
exchange: Mapped[str | None] = mapped_column(sa.String(255), comment='低级别 AMQP 路由的交换机')
|
||||||
routing_key: Mapped[str | None] = mapped_column(String(255), comment='低级别 AMQP 路由的路由密钥')
|
routing_key: Mapped[str | None] = mapped_column(sa.String(255), comment='低级别 AMQP 路由的路由密钥')
|
||||||
start_time: Mapped[datetime | None] = mapped_column(TimeZone, comment='任务开始触发的时间')
|
start_time: Mapped[datetime | None] = mapped_column(TimeZone, comment='任务开始触发的时间')
|
||||||
expire_time: Mapped[datetime | None] = mapped_column(TimeZone, comment='任务不再触发的截止时间')
|
expire_time: Mapped[datetime | None] = mapped_column(TimeZone, comment='任务不再触发的截止时间')
|
||||||
expire_seconds: Mapped[int | None] = mapped_column(comment='任务不再触发的秒数时间差')
|
expire_seconds: Mapped[int | None] = mapped_column(comment='任务不再触发的秒数时间差')
|
||||||
type: Mapped[int] = mapped_column(comment='调度类型(0间隔 1定时)')
|
type: Mapped[int] = mapped_column(comment='调度类型(0间隔 1定时)')
|
||||||
interval_every: Mapped[int | None] = mapped_column(comment='任务再次运行前的间隔周期数')
|
interval_every: Mapped[int | None] = mapped_column(comment='任务再次运行前的间隔周期数')
|
||||||
interval_period: Mapped[str | None] = mapped_column(String(255), comment='任务运行之间的周期类型')
|
interval_period: Mapped[str | None] = mapped_column(sa.String(255), comment='任务运行之间的周期类型')
|
||||||
crontab: Mapped[str | None] = mapped_column(String(50), default='* * * * *', comment='任务运行的 Crontab 计划')
|
crontab: Mapped[str | None] = mapped_column(sa.String(50), default='* * * * *', comment='任务运行的 Crontab 计划')
|
||||||
one_off: Mapped[bool] = mapped_column(
|
one_off: Mapped[bool] = mapped_column(default=False, comment='是否仅运行一次')
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
enabled: Mapped[bool] = mapped_column(default=True, comment='是否启用任务')
|
||||||
default=False,
|
|
||||||
comment='是否仅运行一次',
|
|
||||||
)
|
|
||||||
enabled: Mapped[bool] = mapped_column(
|
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
|
||||||
default=True,
|
|
||||||
comment='是否启用任务',
|
|
||||||
)
|
|
||||||
total_run_count: Mapped[int] = mapped_column(default=0, comment='任务触发的总次数')
|
total_run_count: Mapped[int] = mapped_column(default=0, comment='任务触发的总次数')
|
||||||
last_run_time: Mapped[datetime | None] = mapped_column(TimeZone, default=None, comment='任务最后触发的时间')
|
last_run_time: Mapped[datetime | None] = mapped_column(TimeZone, default=None, comment='任务最后触发的时间')
|
||||||
remark: Mapped[str | None] = mapped_column(
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|
||||||
no_changes: bool = False
|
no_changes: bool = False
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,20 @@ from celery import shared_task
|
|||||||
|
|
||||||
from backend.app.admin.service.login_log_service import login_log_service
|
from backend.app.admin.service.login_log_service import login_log_service
|
||||||
from backend.app.admin.service.opera_log_service import opera_log_service
|
from backend.app.admin.service.opera_log_service import opera_log_service
|
||||||
|
from backend.database.db import async_db_session
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
async def delete_db_opera_log() -> str:
|
async def delete_db_opera_log() -> str:
|
||||||
"""自动删除数据库操作日志"""
|
"""自动删除数据库操作日志"""
|
||||||
await opera_log_service.delete_all()
|
async with async_db_session.begin() as db:
|
||||||
return 'Success'
|
await opera_log_service.delete_all(db=db)
|
||||||
|
return 'Success'
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
async def delete_db_login_log() -> str:
|
async def delete_db_login_log() -> str:
|
||||||
"""自动删除数据库登录日志"""
|
"""自动删除数据库登录日志"""
|
||||||
await login_log_service.delete_all()
|
async with async_db_session.begin() as db:
|
||||||
return 'Success'
|
await login_log_service.delete_all(db=db)
|
||||||
|
return 'Success'
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ class DatabaseScheduler(Scheduler):
|
|||||||
"""获取所有任务调度"""
|
"""获取所有任务调度"""
|
||||||
async with async_db_session() as db:
|
async with async_db_session() as db:
|
||||||
logger.debug('DatabaseScheduler: Fetching database schedule')
|
logger.debug('DatabaseScheduler: Fetching database schedule')
|
||||||
stmt = select(TaskScheduler).where(TaskScheduler.enabled == 1)
|
stmt = select(TaskScheduler).where(TaskScheduler.enabled == True) # noqa: E712
|
||||||
query = await db.execute(stmt)
|
query = await db.execute(stmt)
|
||||||
schedulers = query.scalars().all()
|
schedulers = query.scalars().all()
|
||||||
s = {}
|
s = {}
|
||||||
|
|||||||
+2
-1
@@ -145,7 +145,8 @@ async def import_table(
|
|||||||
) -> None:
|
) -> None:
|
||||||
try:
|
try:
|
||||||
obj = ImportParam(app=app, table_schema=table_schema, table_name=table_name)
|
obj = ImportParam(app=app, table_schema=table_schema, table_name=table_name)
|
||||||
await gen_service.import_business_and_model(obj=obj)
|
async with async_db_session.begin() as db:
|
||||||
|
await gen_service.import_business_and_model(db=db, obj=obj)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise cappa.Exit(e.msg if isinstance(e, BaseExceptionError) else str(e), code=1)
|
raise cappa.Exit(e.msg if isinstance(e, BaseExceptionError) else str(e), code=1)
|
||||||
|
|
||||||
|
|||||||
@@ -46,16 +46,14 @@ async def _validation_exception_handler(exc: RequestValidationError | Validation
|
|||||||
if i18n.current_language != 'en-US':
|
if i18n.current_language != 'en-US':
|
||||||
custom_message = t(f'pydantic.{error["type"]}')
|
custom_message = t(f'pydantic.{error["type"]}')
|
||||||
if custom_message:
|
if custom_message:
|
||||||
ctx = error.get('ctx')
|
error_ctx = error.get('ctx')
|
||||||
if not ctx:
|
if not error_ctx:
|
||||||
error['msg'] = custom_message
|
error['msg'] = custom_message
|
||||||
else:
|
else:
|
||||||
ctx_error = ctx.get('error')
|
e = error_ctx.get('error')
|
||||||
if ctx_error:
|
if e:
|
||||||
error['msg'] = custom_message.format(**ctx)
|
error['msg'] = custom_message.format(**error_ctx)
|
||||||
error['ctx']['error'] = (
|
error['ctx']['error'] = e.__str__().replace("'", '"') if isinstance(e, Exception) else None
|
||||||
ctx_error.__str__().replace("'", '"') if isinstance(ctx_error, Exception) else None
|
|
||||||
)
|
|
||||||
errors.append(error)
|
errors.append(error)
|
||||||
error = errors[0]
|
error = errors[0]
|
||||||
if error.get('type') == 'json_invalid':
|
if error.get('type') == 'json_invalid':
|
||||||
|
|||||||
+22
-7
@@ -1,10 +1,12 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, DateTime, TypeDecorator
|
from sqlalchemy import BigInteger, DateTime, Text, TypeDecorator
|
||||||
|
from sqlalchemy.dialects.mysql import LONGTEXT
|
||||||
from sqlalchemy.ext.asyncio import AsyncAttrs
|
from sqlalchemy.ext.asyncio import AsyncAttrs
|
||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, declared_attr, mapped_column
|
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, declared_attr, mapped_column
|
||||||
|
|
||||||
|
from backend.core.conf import settings
|
||||||
from backend.utils.snowflake import snowflake
|
from backend.utils.snowflake import snowflake
|
||||||
from backend.utils.timezone import timezone
|
from backend.utils.timezone import timezone
|
||||||
|
|
||||||
@@ -41,16 +43,21 @@ snowflake_id_key = Annotated[
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Mixin: 一种面向对象编程概念, 使结构变得更加清晰, `Wiki <https://en.wikipedia.org/wiki/Mixin/>`__
|
class UniversalText(TypeDecorator[str]):
|
||||||
class UserMixin(MappedAsDataclass):
|
"""PostgreSQL、MySQL 兼容性(长)文本类型"""
|
||||||
"""用户 Mixin 数据类"""
|
|
||||||
|
|
||||||
created_by: Mapped[int] = mapped_column(sort_order=998, comment='创建者')
|
impl = LONGTEXT if settings.DATABASE_TYPE == 'mysql' else Text
|
||||||
updated_by: Mapped[int | None] = mapped_column(init=False, default=None, sort_order=998, comment='修改者')
|
cache_ok = True
|
||||||
|
|
||||||
|
def process_bind_param(self, value: str | None, dialect) -> str | None: # noqa: ANN001
|
||||||
|
return value
|
||||||
|
|
||||||
|
def process_result_value(self, value: str | None, dialect) -> str | None: # noqa: ANN001
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class TimeZone(TypeDecorator[datetime]):
|
class TimeZone(TypeDecorator[datetime]):
|
||||||
"""时区感知 DateTime"""
|
"""PostgreSQL、MySQL 兼容性时区感知类型"""
|
||||||
|
|
||||||
impl = DateTime(timezone=True)
|
impl = DateTime(timezone=True)
|
||||||
cache_ok = True
|
cache_ok = True
|
||||||
@@ -71,6 +78,14 @@ class TimeZone(TypeDecorator[datetime]):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
# Mixin: 一种面向对象编程概念, 使结构变得更加清晰, `Wiki <https://en.wikipedia.org/wiki/Mixin/>`__
|
||||||
|
class UserMixin(MappedAsDataclass):
|
||||||
|
"""用户 Mixin 数据类"""
|
||||||
|
|
||||||
|
created_by: Mapped[int] = mapped_column(sort_order=998, comment='创建者')
|
||||||
|
updated_by: Mapped[int | None] = mapped_column(init=False, default=None, sort_order=998, comment='修改者')
|
||||||
|
|
||||||
|
|
||||||
class DateTimeMixin(MappedAsDataclass):
|
class DateTimeMixin(MappedAsDataclass):
|
||||||
"""日期时间 Mixin 数据类"""
|
"""日期时间 Mixin 数据类"""
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.plugin.code_generator.model import GenColumn
|
from backend.plugin.code_generator.model import GenColumn
|
||||||
@@ -19,21 +18,21 @@ class GenBusiness(Base):
|
|||||||
__tablename__ = 'gen_business'
|
__tablename__ = 'gen_business'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
app_name: Mapped[str] = mapped_column(String(50), comment='应用名称(英文)')
|
app_name: Mapped[str] = mapped_column(sa.String(50), comment='应用名称(英文)')
|
||||||
table_name: Mapped[str] = mapped_column(String(255), unique=True, comment='表名称(英文)')
|
table_name: Mapped[str] = mapped_column(sa.String(255), unique=True, comment='表名称(英文)')
|
||||||
doc_comment: Mapped[str] = mapped_column(String(255), comment='文档注释(用于函数/参数文档)')
|
doc_comment: Mapped[str] = mapped_column(sa.String(255), comment='文档注释(用于函数/参数文档)')
|
||||||
table_comment: Mapped[str | None] = mapped_column(String(255), default=None, comment='表描述')
|
table_comment: Mapped[str | None] = mapped_column(sa.String(255), default=None, comment='表描述')
|
||||||
# relate_model_fk: Mapped[int | None] = mapped_column(default=None, comment='关联表外键')
|
# relate_model_fk: Mapped[int | None] = mapped_column(default=None, comment='关联表外键')
|
||||||
class_name: Mapped[str | None] = mapped_column(String(50), default=None, comment='基础类名(默认为英文表名称)')
|
class_name: Mapped[str | None] = mapped_column(sa.String(50), default=None, comment='基础类名(默认为英文表名称)')
|
||||||
schema_name: Mapped[str | None] = mapped_column(String(50), default=None, comment='Schema 名称 (默认为英文表名称)')
|
schema_name: Mapped[str | None] = mapped_column(
|
||||||
filename: Mapped[str | None] = mapped_column(String(50), default=None, comment='基础文件名(默认为英文表名称)')
|
sa.String(50), default=None, comment='Schema 名称 (默认为英文表名称)'
|
||||||
default_datetime_column: Mapped[bool] = mapped_column(default=True, comment='是否存在默认时间列')
|
|
||||||
api_version: Mapped[str] = mapped_column(String(20), default='v1', comment='代码生成 api 版本,默认为 v1')
|
|
||||||
gen_path: Mapped[str | None] = mapped_column(String(255), default=None, comment='代码生成路径(默认为 app 根路径)')
|
|
||||||
remark: Mapped[str | None] = mapped_column(
|
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
)
|
||||||
|
filename: Mapped[str | None] = mapped_column(sa.String(50), default=None, comment='基础文件名(默认为英文表名称)')
|
||||||
|
default_datetime_column: Mapped[bool] = mapped_column(default=True, comment='是否存在默认时间列')
|
||||||
|
api_version: Mapped[str] = mapped_column(sa.String(20), default='v1', comment='代码生成 api 版本,默认为 v1')
|
||||||
|
gen_path: Mapped[str | None] = mapped_column(
|
||||||
|
sa.String(255), default=None, comment='代码生成路径(默认为 app 根路径)'
|
||||||
|
)
|
||||||
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
# 代码生成业务模型列一对多
|
# 代码生成业务模型列一对多
|
||||||
gen_column: Mapped[list[GenColumn]] = relationship(init=False, back_populates='gen_business')
|
gen_column: Mapped[list[GenColumn]] = relationship(init=False, back_populates='gen_business')
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, ForeignKey, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import DataClassBase, id_key
|
from backend.common.model import DataClassBase, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.plugin.code_generator.model import GenBusiness
|
from backend.plugin.code_generator.model import GenBusiness
|
||||||
@@ -19,15 +18,11 @@ class GenColumn(DataClassBase):
|
|||||||
__tablename__ = 'gen_column'
|
__tablename__ = 'gen_column'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(50), comment='列名称')
|
name: Mapped[str] = mapped_column(sa.String(50), comment='列名称')
|
||||||
comment: Mapped[str | None] = mapped_column(String(255), default=None, comment='列描述')
|
comment: Mapped[str | None] = mapped_column(sa.String(255), default=None, comment='列描述')
|
||||||
type: Mapped[str] = mapped_column(String(20), default='String', comment='SQLA 模型列类型')
|
type: Mapped[str] = mapped_column(sa.String(20), default='String', comment='SQLA 模型列类型')
|
||||||
pd_type: Mapped[str] = mapped_column(String(20), default='str', comment='列类型对应的 pydantic 类型')
|
pd_type: Mapped[str] = mapped_column(sa.String(20), default='str', comment='列类型对应的 pydantic 类型')
|
||||||
default: Mapped[str | None] = mapped_column(
|
default: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='列默认值')
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='列默认值',
|
|
||||||
)
|
|
||||||
sort: Mapped[int | None] = mapped_column(default=1, comment='列排序')
|
sort: Mapped[int | None] = mapped_column(default=1, comment='列排序')
|
||||||
length: Mapped[int] = mapped_column(default=0, comment='列长度')
|
length: Mapped[int] = mapped_column(default=0, comment='列长度')
|
||||||
is_pk: Mapped[bool] = mapped_column(default=False, comment='是否主键')
|
is_pk: Mapped[bool] = mapped_column(default=False, comment='是否主键')
|
||||||
@@ -35,9 +30,6 @@ class GenColumn(DataClassBase):
|
|||||||
|
|
||||||
# 代码生成业务模型列一对多
|
# 代码生成业务模型列一对多
|
||||||
gen_business_id: Mapped[int] = mapped_column(
|
gen_business_id: Mapped[int] = mapped_column(
|
||||||
BigInteger,
|
sa.BigInteger, sa.ForeignKey('gen_business.id', ondelete='CASCADE'), default=0, comment='代码生成业务ID'
|
||||||
ForeignKey('gen_business.id', ondelete='CASCADE'),
|
|
||||||
default=0,
|
|
||||||
comment='代码生成业务ID',
|
|
||||||
)
|
)
|
||||||
gen_business: Mapped[GenBusiness | None] = relationship(init=False, back_populates='gen_column')
|
gen_business: Mapped[GenBusiness | None] = relationship(init=False, back_populates='gen_column')
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ async def get_{{ table_name }}(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def get_{{ table_name }}s_paginated(db: CurrentSession) -> ResponseSchemaModel[PageData[Get{{ schema_name }}Detail]]:
|
async def get_{{ table_name }}s_paginated(db: CurrentSession) -> ResponseSchemaModel[PageData[Get{{ schema_name }}Detail]]:
|
||||||
page_data = = await {{ table_name }}_service.get_list(db=db)
|
page_data = await {{ table_name }}_service.get_list(db=db)
|
||||||
return response_base.success(data=page_data)
|
return response_base.success(data=page_data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
from sqlalchemy import Boolean, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import INTEGER, TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
|
|
||||||
class Config(Base):
|
class Config(Base):
|
||||||
@@ -12,17 +11,9 @@ class Config(Base):
|
|||||||
__tablename__ = 'sys_config'
|
__tablename__ = 'sys_config'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(20), comment='名称')
|
name: Mapped[str] = mapped_column(sa.String(20), comment='名称')
|
||||||
type: Mapped[str | None] = mapped_column(String(20), server_default=None, comment='类型')
|
type: Mapped[str | None] = mapped_column(sa.String(20), server_default=None, comment='类型')
|
||||||
key: Mapped[str] = mapped_column(String(50), unique=True, comment='键名')
|
key: Mapped[str] = mapped_column(sa.String(50), unique=True, comment='键名')
|
||||||
value: Mapped[str] = mapped_column(LONGTEXT().with_variant(TEXT, 'postgresql'), comment='键值')
|
value: Mapped[str] = mapped_column(UniversalText, comment='键值')
|
||||||
is_frontend: Mapped[bool] = mapped_column(
|
is_frontend: Mapped[bool] = mapped_column(default=False, comment='是否前端')
|
||||||
Boolean().with_variant(INTEGER, 'postgresql'),
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
default=False,
|
|
||||||
comment='是否前端',
|
|
||||||
)
|
|
||||||
remark: Mapped[str | None] = mapped_column(
|
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
insert into sys_config (id, name, type, `key`, value, is_frontend, remark, created_time, updated_time)
|
insert into sys_config (id, name, type, `key`, value, is_frontend, remark, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(1, '状态', 'EMAIL', 'EMAIL_STATUS', '1', 0, null, now(), null),
|
(1, '状态', 'EMAIL', 'EMAIL_STATUS', '1', false, null, now(), null),
|
||||||
(2, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', 0, null, now(), null),
|
(2, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', false, null, now(), null),
|
||||||
(3, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', 0, null, now(), null),
|
(3, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', false, null, now(), null),
|
||||||
(4, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', 0, null, now(), null),
|
(4, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', false, null, now(), null),
|
||||||
(5, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', 0, null, now(), null),
|
(5, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', false, null, now(), null),
|
||||||
(6, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', 0, null, now(), null);
|
(6, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', false, null, now(), null);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
insert into sys_config (id, name, type, `key`, value, is_frontend, remark, created_time, updated_time)
|
insert into sys_config (id, name, type, `key`, value, is_frontend, remark, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(2069061886627938304, '状态', 'EMAIL', 'EMAIL_STATUS', '1', 0, null, now(), null),
|
(2069061886627938304, '状态', 'EMAIL', 'EMAIL_STATUS', '1', false, null, now(), null),
|
||||||
(2069061886627938305, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', 0, null, now(), null),
|
(2069061886627938305, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', false, null, now(), null),
|
||||||
(2069061886627938306, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', 0, null, now(), null),
|
(2069061886627938306, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', false, null, now(), null),
|
||||||
(2069061886627938307, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', 0, null, now(), null),
|
(2069061886627938307, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', false, null, now(), null),
|
||||||
(2069061886627938308, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', 0, null, now(), null),
|
(2069061886627938308, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', false, null, now(), null),
|
||||||
(2069061886627938309, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', 0, null, now(), null);
|
(2069061886627938309, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', false, null, now(), null);
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
insert into sys_config (id, name, type, "key", value, is_frontend, remark, created_time, updated_time)
|
insert into sys_config (id, name, type, "key", value, is_frontend, remark, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(1, '状态', 'EMAIL', 'EMAIL_STATUS', '1', 0, null, now(), null),
|
(1, '状态', 'EMAIL', 'EMAIL_STATUS', '1', false, null, now(), null),
|
||||||
(2, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', 0, null, now(), null),
|
(2, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', false, null, now(), null),
|
||||||
(3, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', 0, null, now(), null),
|
(3, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', false, null, now(), null),
|
||||||
(4, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', 0, null, now(), null),
|
(4, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', false, null, now(), null),
|
||||||
(5, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', 0, null, now(), null),
|
(5, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', false, null, now(), null),
|
||||||
(6, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', 0, null, now(), null);
|
(6, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', false, null, now(), null);
|
||||||
|
|
||||||
-- reset auto-increment values for each table based on max id
|
|
||||||
select setval(pg_get_serial_sequence('sys_config', 'id'),coalesce(max(id), 0) + 1, true) from sys_config;
|
select setval(pg_get_serial_sequence('sys_config', 'id'),coalesce(max(id), 0) + 1, true) from sys_config;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
insert into sys_config (id, name, type, "key", value, is_frontend, remark, created_time, updated_time)
|
insert into sys_config (id, name, type, "key", value, is_frontend, remark, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(2069061886627938304, '状态', 'EMAIL', 'EMAIL_STATUS', '1', 0, null, now(), null),
|
(2069061886627938304, '状态', 'EMAIL', 'EMAIL_STATUS', '1', false, null, now(), null),
|
||||||
(2069061886627938305, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', 0, null, now(), null),
|
(2069061886627938305, '服务器地址', 'EMAIL', 'EMAIL_HOST', 'smtp.qq.com', false, null, now(), null),
|
||||||
(2069061886627938306, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', 0, null, now(), null),
|
(2069061886627938306, '服务器端口', 'EMAIL', 'EMAIL_PORT', '465', false, null, now(), null),
|
||||||
(2069061886627938307, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', 0, null, now(), null),
|
(2069061886627938307, '邮箱账号', 'EMAIL', 'EMAIL_USERNAME', 'fba@qq.com', false, null, now(), null),
|
||||||
(2069061886627938308, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', 0, null, now(), null),
|
(2069061886627938308, '邮箱密码', 'EMAIL', 'EMAIL_PASSWORD', '', false, null, now(), null),
|
||||||
(2069061886627938309, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', 0, null, now(), null);
|
(2069061886627938309, 'SSL 加密', 'EMAIL', 'EMAIL_SSL', '1', false, null, now(), null);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
from sqlalchemy import Select
|
from sqlalchemy import Select, and_
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy_crud_plus import CRUDPlus
|
from sqlalchemy_crud_plus import CRUDPlus
|
||||||
|
|
||||||
@@ -79,15 +79,16 @@ class CRUDDictData(CRUDPlus[DictData]):
|
|||||||
|
|
||||||
return await self.select_order('id', 'desc', load_strategies={'type': 'noload'}, **filters)
|
return await self.select_order('id', 'desc', load_strategies={'type': 'noload'}, **filters)
|
||||||
|
|
||||||
async def get_by_label(self, db: AsyncSession, label: str) -> DictData | None:
|
async def get_by_label_and_type_code(self, db: AsyncSession, label: str, type_code: str) -> DictData | None:
|
||||||
"""
|
"""
|
||||||
通过标签获取字典数据
|
通过标签获取字典数据
|
||||||
|
|
||||||
:param db: 数据库会话
|
:param db: 数据库会话
|
||||||
:param label: 字典标签
|
:param label: 字典标签
|
||||||
|
:param type_code: 字典类型编码
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return await self.select_model_by_column(db, label=label)
|
return await self.select_model_by_column(db, and_(self.model.label == label, self.model.type_code == type_code))
|
||||||
|
|
||||||
async def create(self, db: AsyncSession, obj: CreateDictDataParam, type_code: str) -> None:
|
async def create(self, db: AsyncSession, obj: CreateDictDataParam, type_code: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.plugin.dict.model import DictType
|
from backend.plugin.dict.model import DictType
|
||||||
@@ -19,22 +18,16 @@ class DictData(Base):
|
|||||||
__tablename__ = 'sys_dict_data'
|
__tablename__ = 'sys_dict_data'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
type_code: Mapped[str] = mapped_column(String(32), comment='对应的字典类型编码')
|
type_code: Mapped[str] = mapped_column(sa.String(32), comment='对应的字典类型编码')
|
||||||
label: Mapped[str] = mapped_column(String(32), comment='字典标签')
|
label: Mapped[str] = mapped_column(sa.String(32), comment='字典标签')
|
||||||
value: Mapped[str] = mapped_column(String(32), comment='字典值')
|
value: Mapped[str] = mapped_column(sa.String(32), comment='字典值')
|
||||||
color: Mapped[str | None] = mapped_column(String(32), default=None, comment='标签颜色')
|
color: Mapped[str | None] = mapped_column(sa.String(32), default=None, comment='标签颜色')
|
||||||
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='状态(0停用 1正常)')
|
||||||
remark: Mapped[str | None] = mapped_column(
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|
||||||
# 字典类型一对多
|
# 字典类型一对多
|
||||||
type_id: Mapped[int] = mapped_column(
|
type_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey('sys_dict_type.id', ondelete='CASCADE'),
|
sa.ForeignKey('sys_dict_type.id', ondelete='CASCADE'), default=0, comment='字典类型关联ID'
|
||||||
default=0,
|
|
||||||
comment='字典类型关联ID',
|
|
||||||
)
|
)
|
||||||
type: Mapped[DictType] = relationship(init=False, back_populates='datas')
|
type: Mapped[DictType] = relationship(init=False, back_populates='datas')
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.dialects.postgresql import TEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from backend.plugin.dict.model import DictData
|
from backend.plugin.dict.model import DictData
|
||||||
@@ -19,13 +18,9 @@ class DictType(Base):
|
|||||||
__tablename__ = 'sys_dict_type'
|
__tablename__ = 'sys_dict_type'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
name: Mapped[str] = mapped_column(String(32), comment='字典类型名称')
|
name: Mapped[str] = mapped_column(sa.String(32), comment='字典类型名称')
|
||||||
code: Mapped[str] = mapped_column(String(32), unique=True, comment='字典类型编码')
|
code: Mapped[str] = mapped_column(sa.String(32), unique=True, comment='字典类型编码')
|
||||||
remark: Mapped[str | None] = mapped_column(
|
remark: Mapped[str | None] = mapped_column(UniversalText, default=None, comment='备注')
|
||||||
LONGTEXT().with_variant(TEXT, 'postgresql'),
|
|
||||||
default=None,
|
|
||||||
comment='备注',
|
|
||||||
)
|
|
||||||
|
|
||||||
# 字典类型一对多
|
# 字典类型一对多
|
||||||
datas: Mapped[list[DictData]] = relationship(init=False, back_populates='type')
|
datas: Mapped[list[DictData]] = relationship(init=False, back_populates='type')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[plugin]
|
[plugin]
|
||||||
summary = '数据字典'
|
summary = '数据字典'
|
||||||
version = '0.0.6'
|
version = '0.0.7'
|
||||||
description = '通常用于约束前端工程数据展示'
|
description = '通常用于约束前端工程数据展示'
|
||||||
author = 'wu-clan'
|
author = 'wu-clan'
|
||||||
|
|
||||||
|
|||||||
@@ -94,13 +94,12 @@ class DictDataService:
|
|||||||
:param obj: 字典数据创建参数
|
:param obj: 字典数据创建参数
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dict_data = await dict_data_dao.get_by_label(db, obj.label)
|
|
||||||
if dict_data:
|
|
||||||
raise errors.ConflictError(msg='字典数据已存在')
|
|
||||||
dict_type = await dict_type_dao.get(db, obj.type_id)
|
dict_type = await dict_type_dao.get(db, obj.type_id)
|
||||||
if not dict_type:
|
if not dict_type:
|
||||||
raise errors.NotFoundError(msg='字典类型不存在')
|
raise errors.NotFoundError(msg='字典类型不存在')
|
||||||
|
dict_data = await dict_data_dao.get_by_label_and_type_code(db, obj.label, dict_type.code)
|
||||||
|
if dict_data:
|
||||||
|
raise errors.ConflictError(msg='字典数据已存在')
|
||||||
await dict_data_dao.create(db, obj, dict_type.code)
|
await dict_data_dao.create(db, obj, dict_type.code)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -117,11 +116,13 @@ class DictDataService:
|
|||||||
dict_data = await dict_data_dao.get(db, pk)
|
dict_data = await dict_data_dao.get(db, pk)
|
||||||
if not dict_data:
|
if not dict_data:
|
||||||
raise errors.NotFoundError(msg='字典数据不存在')
|
raise errors.NotFoundError(msg='字典数据不存在')
|
||||||
if dict_data.label != obj.label and await dict_data_dao.get_by_label(db, obj.label):
|
|
||||||
raise errors.ConflictError(msg='字典数据已存在')
|
|
||||||
dict_type = await dict_type_dao.get(db, obj.type_id)
|
dict_type = await dict_type_dao.get(db, obj.type_id)
|
||||||
if not dict_type:
|
if not dict_type:
|
||||||
raise errors.NotFoundError(msg='字典类型不存在')
|
raise errors.NotFoundError(msg='字典类型不存在')
|
||||||
|
if dict_data.label != obj.label and await dict_data_dao.get_by_label_and_type_code(
|
||||||
|
db, obj.label, dict_type.code
|
||||||
|
):
|
||||||
|
raise errors.ConflictError(msg='字典数据已存在')
|
||||||
count = await dict_data_dao.update(db, pk, obj, dict_type.code)
|
count = await dict_data_dao.update(db, pk, obj, dict_type.code)
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
|||||||
@@ -51,3 +51,6 @@ values
|
|||||||
(34, 'user_online_status', '在线', '1', 'success', 2, 1, '用户在线状态', 11, now(), null),
|
(34, 'user_online_status', '在线', '1', 'success', 2, 1, '用户在线状态', 11, now(), null),
|
||||||
(35, 'sys_plugin_type', '压缩包', '0', 'gold', 1, 1, '插件类型-压缩包', 12, now(), null),
|
(35, 'sys_plugin_type', '压缩包', '0', 'gold', 1, 1, '插件类型-压缩包', 12, now(), null),
|
||||||
(36, 'sys_plugin_type', 'GIT', '1', 'processing', 2, 1, '插件类型-GIT', 12, now(), null);
|
(36, 'sys_plugin_type', 'GIT', '1', 'processing', 2, 1, '插件类型-GIT', 12, now(), null);
|
||||||
|
|
||||||
|
select setval(pg_get_serial_sequence('sys_dict_type', 'id'),coalesce(max(id), 0) + 1, true) from sys_dict_type;
|
||||||
|
select setval(pg_get_serial_sequence('sys_dict_data', 'id'),coalesce(max(id), 0) + 1, true) from sys_dict_data;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from sqlalchemy import TEXT, String
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, UniversalText, id_key
|
||||||
|
|
||||||
|
|
||||||
class Notice(Base):
|
class Notice(Base):
|
||||||
@@ -11,7 +11,7 @@ class Notice(Base):
|
|||||||
__tablename__ = 'sys_notice'
|
__tablename__ = 'sys_notice'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
title: Mapped[str] = mapped_column(String(50), comment='标题')
|
title: Mapped[str] = mapped_column(sa.String(50), comment='标题')
|
||||||
type: Mapped[int] = mapped_column(comment='类型(0:通知、1:公告)')
|
type: Mapped[int] = mapped_column(comment='类型(0:通知、1:公告)')
|
||||||
status: Mapped[int] = mapped_column(comment='状态(0:隐藏、1:显示)')
|
status: Mapped[int] = mapped_column(comment='状态(0:隐藏、1:显示)')
|
||||||
content: Mapped[str] = mapped_column(LONGTEXT().with_variant(TEXT, 'postgresql'), comment='内容')
|
content: Mapped[str] = mapped_column(UniversalText, comment='内容')
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, ForeignKey, String
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from backend.common.model import Base, id_key
|
from backend.common.model import Base, id_key
|
||||||
@@ -17,13 +18,11 @@ class UserSocial(Base):
|
|||||||
__tablename__ = 'sys_user_social'
|
__tablename__ = 'sys_user_social'
|
||||||
|
|
||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
sid: Mapped[str] = mapped_column(String(255), comment='第三方用户 ID')
|
sid: Mapped[str] = mapped_column(sa.String(255), comment='第三方用户 ID')
|
||||||
source: Mapped[str] = mapped_column(String(20), comment='第三方用户来源')
|
source: Mapped[str] = mapped_column(sa.String(20), comment='第三方用户来源')
|
||||||
|
|
||||||
# 用户社交信息一对多
|
# 用户社交信息一对多
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
BigInteger,
|
sa.BigInteger, sa.ForeignKey('sys_user.id', ondelete='CASCADE'), comment='用户关联ID'
|
||||||
ForeignKey('sys_user.id', ondelete='CASCADE'),
|
|
||||||
comment='用户关联ID',
|
|
||||||
)
|
)
|
||||||
user: Mapped[User | None] = relationship(init=False, backref='socials')
|
user: Mapped[User | None] = relationship(init=False, backref='socials')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||||
values (2048601258595581952, '测试', 0, null, null, null, 1, 0, null, now(), null);
|
values (2048601258595581952, '测试', 0, null, null, null, 1, false, null, now(), null);
|
||||||
|
|
||||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
@@ -82,7 +82,7 @@ values
|
|||||||
(2049629108257816588, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 2049629108257816580, '2025-06-26 20:29:06', null);
|
(2049629108257816588, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 2049629108257816580, '2025-06-26 20:29:06', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||||
values (2048601263515500544, '测试', 1, 1, null, now(), null);
|
values (2048601263515500544, '测试', 1, true, null, now(), null);
|
||||||
|
|
||||||
insert into sys_role_menu (id, role_id, menu_id)
|
insert into sys_role_menu (id, role_id, menu_id)
|
||||||
values
|
values
|
||||||
@@ -91,10 +91,10 @@ values
|
|||||||
(2048601263708438528, 2048601263515500544, 2049629108245233666),
|
(2048601263708438528, 2048601263515500544, 2049629108245233666),
|
||||||
(2048601263775547392, 2048601263515500544, 2049629108253622282);
|
(2048601263775547392, 2048601263515500544, 2049629108253622282);
|
||||||
|
|
||||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
insert into sys_user (id, uuid, username, nickname, password, salt, email, status, is_superuser, is_staff, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(2048601263834267648, uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', unhex('24326224313224387932654E7563583139566A6D5A33745968424C634F'), 'admin@example.com', 1, 1, 1, 1, null, null, now(), now(), 2048601258595581952, now(), null),
|
(2048601263834267648, uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', unhex('24326224313224387932654E7563583139566A6D5A33745968424C634F'), 'admin@example.com', 1, true, true, true, null, null, now(), now(), 2048601258595581952, now(), null),
|
||||||
(2049946297615646720, uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', unhex('24326224313224424D6958734E514167547837614E63376B56676E7765'), 'test@example.com', 0, 0, 1, 0, null, null, now(), now(), 2048601258595581952, now(), null);
|
(2049946297615646720, uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', unhex('24326224313224424D6958734E514167547837614E63376B56676E7765'), 'test@example.com', 1, false, false, false, null, null, now(), now(), 2048601258595581952, now(), null);
|
||||||
|
|
||||||
insert into sys_user_role (id, user_id, role_id)
|
insert into sys_user_role (id, user_id, role_id)
|
||||||
values
|
values
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||||
values (1, '测试', 0, null, null, null, 1, 0, null, now(), null);
|
values (1, '测试', 0, null, null, null, 1, false, null, now(), null);
|
||||||
|
|
||||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
@@ -82,7 +82,7 @@ values
|
|||||||
(77, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 69, '2025-06-26 20:29:06', null);
|
(77, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 69, '2025-06-26 20:29:06', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||||
values (1, '测试', 1, 1, null, now(), null);
|
values (1, '测试', 1, true, null, now(), null);
|
||||||
|
|
||||||
insert into sys_role_menu (id, role_id, menu_id)
|
insert into sys_role_menu (id, role_id, menu_id)
|
||||||
values
|
values
|
||||||
@@ -91,10 +91,10 @@ values
|
|||||||
(3, 1, 3),
|
(3, 1, 3),
|
||||||
(4, 1, 53);
|
(4, 1, 53);
|
||||||
|
|
||||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
insert into sys_user (id, uuid, username, nickname, password, salt, email, status, is_superuser, is_staff, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(1, uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', unhex('24326224313224387932654E7563583139566A6D5A33745968424C634F'), 'admin@example.com', 1, 1, 1, 1, null, null, now(), now(), 1, now(), null),
|
(1, uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', unhex('24326224313224387932654E7563583139566A6D5A33745968424C634F'), 'admin@example.com', 1, true, true, true, null, null, now(), now(), 1, now(), null),
|
||||||
(2, uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', unhex('24326224313224424D6958734E514167547837614E63376B56676E7765'), 'test@example.com', 0, 0, 1, 0, null, null, now(), now(), 1, now(), null);
|
(2, uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', unhex('24326224313224424D6958734E514167547837614E63376B56676E7765'), 'test@example.com', 1, false, false, false, null, null, now(), now(), 1, now(), null);
|
||||||
|
|
||||||
insert into sys_user_role (id, user_id, role_id)
|
insert into sys_user_role (id, user_id, role_id)
|
||||||
values
|
values
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||||
values (2048601264366944256, '测试', 0, null, null, null, 1, 0, null, now(), null);
|
values (2048601264366944256, '测试', 0, null, null, null, 1, false, null, now(), null);
|
||||||
|
|
||||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
@@ -82,7 +82,7 @@ values
|
|||||||
(2049629108257816588, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 2049629108257816580, '2025-06-26 20:29:06', null);
|
(2049629108257816588, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 2049629108257816580, '2025-06-26 20:29:06', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||||
values (2048601269345583104, '测试', 1, 1, null, now(), null);
|
values (2048601269345583104, '测试', 1, true, null, now(), null);
|
||||||
|
|
||||||
insert into sys_role_menu (id, role_id, menu_id)
|
insert into sys_role_menu (id, role_id, menu_id)
|
||||||
values
|
values
|
||||||
@@ -91,10 +91,10 @@ values
|
|||||||
(2048601269546909696, 2048601269345583104, 2049629108245233666),
|
(2048601269546909696, 2048601269345583104, 2049629108245233666),
|
||||||
(2048601269609824256, 2048601269345583104, 2049629108253622282);
|
(2048601269609824256, 2048601269345583104, 2049629108253622282);
|
||||||
|
|
||||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
insert into sys_user (id, uuid, username, nickname, password, salt, email, status, is_superuser, is_staff, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(2048601269672738816, gen_random_uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', decode('24326224313224387932654E7563583139566A6D5A33745968424C634F', 'hex'), 'admin@example.com', 1, 1, 1, 1, null, null, now(), now(), 2048601264366944256, now(), null),
|
(2048601269672738816, gen_random_uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', decode('24326224313224387932654E7563583139566A6D5A33745968424C634F', 'hex'), 'admin@example.com', 1, true, true, true, null, null, now(), now(), 2048601264366944256, now(), null),
|
||||||
(2049946297615646720, gen_random_uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', decode('24326224313224424D6958734E514167547837614E63376B56676E7765', 'hex'), 'test@example.com', 0, 0, 1, 0, null, null, now(), now(), 2048601264366944256, now(), null);
|
(2049946297615646720, gen_random_uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', decode('24326224313224424D6958734E514167547837614E63376B56676E7765', 'hex'), 'test@example.com', 1, false, false, false, null, null, now(), now(), 2048601264366944256, now(), null);
|
||||||
|
|
||||||
insert into sys_user_role (id, user_id, role_id)
|
insert into sys_user_role (id, user_id, role_id)
|
||||||
values
|
values
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||||
values (1, '测试', 0, null, null, null, 1, 0, null, now(), null);
|
values (1, '测试', 0, null, null, null, 1, false, null, now(), null);
|
||||||
|
|
||||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
@@ -82,7 +82,7 @@ values
|
|||||||
(77, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 69, '2025-06-26 20:29:06', null);
|
(77, '写入', 'WriteGenCode', null, 0, null, 2, null, 'codegen:local:write', 1, 0, 1, '', null, 69, '2025-06-26 20:29:06', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||||
values (1, '测试', 1, 1, null, now(), null);
|
values (1, '测试', 1, true, null, now(), null);
|
||||||
|
|
||||||
insert into sys_role_menu (id, role_id, menu_id)
|
insert into sys_role_menu (id, role_id, menu_id)
|
||||||
values
|
values
|
||||||
@@ -91,10 +91,10 @@ values
|
|||||||
(3, 1, 3),
|
(3, 1, 3),
|
||||||
(4, 1, 53);
|
(4, 1, 53);
|
||||||
|
|
||||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
insert into sys_user (id, uuid, username, nickname, password, salt, email, status, is_superuser, is_staff, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||||
values
|
values
|
||||||
(1, gen_random_uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', decode('24326224313224387932654E7563583139566A6D5A33745968424C634F', 'hex'), 'admin@example.com', 1, 1, 1, 1, null, null, now(), now(), 1, now(), null),
|
(1, gen_random_uuid(), 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', decode('24326224313224387932654E7563583139566A6D5A33745968424C634F', 'hex'), 'admin@example.com', 1, true, true, true, null, null, now(), now(), 1, now(), null),
|
||||||
(2, gen_random_uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', decode('24326224313224424D6958734E514167547837614E63376B56676E7765', 'hex'), 'test@example.com', 0, 0, 1, 0, null, null, now(), now(), 1, now(), null);
|
(2, gen_random_uuid(), 'test', '用户66666', '$2b$12$BMiXsNQAgTx7aNc7kVgnwedXGyUxPEHRnJMFbiikbqHgVoT3y14Za', decode('24326224313224424D6958734E514167547837614E63376B56676E7765', 'hex'), 'test@example.com', 1, false, false, false, null, null, now(), now(), 1, now(), null);
|
||||||
|
|
||||||
insert into sys_user_role (id, user_id, role_id)
|
insert into sys_user_role (id, user_id, role_id)
|
||||||
values
|
values
|
||||||
@@ -117,7 +117,6 @@ values
|
|||||||
(2, 2, 1),
|
(2, 2, 1),
|
||||||
(3, 2, 2);
|
(3, 2, 2);
|
||||||
|
|
||||||
-- reset auto-increment values for each table based on max id
|
|
||||||
select setval(pg_get_serial_sequence('sys_dept', 'id'),coalesce(max(id), 0) + 1, true) from sys_dept;
|
select setval(pg_get_serial_sequence('sys_dept', 'id'),coalesce(max(id), 0) + 1, true) from sys_dept;
|
||||||
select setval(pg_get_serial_sequence('sys_menu', 'id'),coalesce(max(id), 0) + 1, true) from sys_menu;
|
select setval(pg_get_serial_sequence('sys_menu', 'id'),coalesce(max(id), 0) + 1, true) from sys_menu;
|
||||||
select setval(pg_get_serial_sequence('sys_role', 'id'),coalesce(max(id), 0) + 1, true) from sys_role;
|
select setval(pg_get_serial_sequence('sys_role', 'id'),coalesce(max(id), 0) + 1, true) from sys_role;
|
||||||
|
|||||||
+34
-34
@@ -8,9 +8,9 @@ networks:
|
|||||||
- subnet: 172.10.10.0/24
|
- subnet: 172.10.10.0/24
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# 如果你是 postgres 用户,应将 fba_mysql 修改为 fba_postgres
|
# 如果你是 mysql 用户,应将 fba_postgres 修改为 fba_mysql
|
||||||
fba_mysql:
|
fba_postgres:
|
||||||
name: fba_mysql
|
name: fba_postgres
|
||||||
fba_redis:
|
fba_redis:
|
||||||
name: fba_redis
|
name: fba_redis
|
||||||
fba_static:
|
fba_static:
|
||||||
@@ -28,9 +28,9 @@ services:
|
|||||||
image: fba_server:latest
|
image: fba_server:latest
|
||||||
container_name: fba_server
|
container_name: fba_server
|
||||||
restart: always
|
restart: always
|
||||||
# 如果你是 postgres 用户,应将 fba_mysql 修改为 fba_postgres
|
# 如果你是 mysql 用户,应将 fba_postgres 修改为 fba_mysql
|
||||||
depends_on:
|
depends_on:
|
||||||
- fba_mysql
|
- fba_postgres
|
||||||
- fba_redis
|
- fba_redis
|
||||||
- fba_celery
|
- fba_celery
|
||||||
volumes:
|
volumes:
|
||||||
@@ -39,50 +39,50 @@ services:
|
|||||||
- fba_static_upload:/fba/backend/static/upload
|
- fba_static_upload:/fba/backend/static/upload
|
||||||
networks:
|
networks:
|
||||||
- fba_network
|
- fba_network
|
||||||
# 如果你是 postgres 用户,应将 fba_mysql:3306 修改为 fba_postgres:5432
|
# 如果你是 mysql 用户,应将 fba_postgres:5432 修改为 fba_mysql:3306
|
||||||
command:
|
command:
|
||||||
- bash
|
- bash
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
wait-for-it -s fba_mysql:3306 -s fba_redis:6379 -t 300
|
wait-for-it -s fba_postgres:5432 -s fba_redis:6379 -t 300
|
||||||
supervisord -c /etc/supervisor/supervisord.conf
|
supervisord -c /etc/supervisor/supervisord.conf
|
||||||
supervisorctl restart
|
supervisorctl restart
|
||||||
|
|
||||||
fba_mysql:
|
fba_postgres:
|
||||||
image: mysql:8.0.41
|
image: postgres:16
|
||||||
ports:
|
ports:
|
||||||
- "${DOCKER_MYSQL_MAP_PORT:-3306}:3306"
|
- "${DOCKER_POSTGRES_MAP_PORT:-5432}:5432"
|
||||||
container_name: fba_mysql
|
container_name: fba_postgres
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
MYSQL_DATABASE: fba
|
POSTGRES_DB: fba
|
||||||
MYSQL_ROOT_PASSWORD: 123456
|
POSTGRES_PASSWORD: 123456
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
volumes:
|
volumes:
|
||||||
- fba_mysql:/var/lib/mysql
|
- fba_postgres:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- fba_network
|
- fba_network
|
||||||
command:
|
|
||||||
--default-authentication-plugin=mysql_native_password
|
|
||||||
--character-set-server=utf8mb4
|
|
||||||
--collation-server=utf8mb4_general_ci
|
|
||||||
--lower_case_table_names=1
|
|
||||||
|
|
||||||
# # 如果你是 postgres 用户,应保留 fba_postgres 容器脚本并删除 fba_mysql 容器脚本
|
# # 如果你是 mysql 用户,应保留 fba_mysql 容器脚本并删除 fba_postgres 容器脚本
|
||||||
# fba_postgres:
|
# fba_mysql:
|
||||||
# image: postgres:16
|
# image: mysql:8.0.41
|
||||||
# ports:
|
# ports:
|
||||||
# - "${DOCKER_POSTGRES_MAP_PORT:-5432}:5432"
|
# - "${DOCKER_MYSQL_MAP_PORT:-3306}:3306"
|
||||||
# container_name: fba_postgres
|
# container_name: fba_mysql
|
||||||
# restart: always
|
# restart: always
|
||||||
# environment:
|
# environment:
|
||||||
# POSTGRES_DB: fba
|
# MYSQL_DATABASE: fba
|
||||||
# POSTGRES_PASSWORD: 123456
|
# MYSQL_ROOT_PASSWORD: 123456
|
||||||
# TZ: Asia/Shanghai
|
# TZ: Asia/Shanghai
|
||||||
# volumes:
|
# volumes:
|
||||||
# - fba_postgres:/var/lib/postgresql/data
|
# - fba_mysql:/var/lib/mysql
|
||||||
# networks:
|
# networks:
|
||||||
# - fba_network
|
# - fba_network
|
||||||
|
# command:
|
||||||
|
# --default-authentication-plugin=mysql_native_password
|
||||||
|
# --character-set-server=utf8mb4
|
||||||
|
# --collation-server=utf8mb4_general_ci
|
||||||
|
# --lower_case_table_names=1
|
||||||
|
|
||||||
fba_redis:
|
fba_redis:
|
||||||
image: redis
|
image: redis
|
||||||
|
|||||||
+8
-8
@@ -12,7 +12,7 @@ license = { text = "MIT" }
|
|||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dynamic = ['version']
|
dynamic = ['version']
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alembic>=1.16.5",
|
"alembic>=1.17.0",
|
||||||
"asgiref>=3.10.0",
|
"asgiref>=3.10.0",
|
||||||
"asyncmy>=0.2.10",
|
"asyncmy>=0.2.10",
|
||||||
"asyncpg>=0.30.0",
|
"asyncpg>=0.30.0",
|
||||||
@@ -22,12 +22,12 @@ dependencies = [
|
|||||||
# When celery version < 6.0.0
|
# When celery version < 6.0.0
|
||||||
# https://github.com/celery/celery/issues/7874
|
# https://github.com/celery/celery/issues/7874
|
||||||
"celery-aio-pool>=0.1.0rc8",
|
"celery-aio-pool>=0.1.0rc8",
|
||||||
"cryptography>=46.0.2",
|
"cryptography>=46.0.3",
|
||||||
"dulwich>=0.24.2",
|
"dulwich>=0.24.6",
|
||||||
"fast-captcha>=0.3.2",
|
"fast-captcha>=0.3.2",
|
||||||
"fastapi-limiter>=0.1.6",
|
"fastapi-limiter>=0.1.6",
|
||||||
"fastapi-pagination>=0.14.3",
|
"fastapi-pagination>=0.14.3",
|
||||||
"fastapi[standard-no-fastapi-cloud-cli]>=0.119.0",
|
"fastapi[standard-no-fastapi-cloud-cli]>=0.119.1",
|
||||||
"flower>=2.0.1",
|
"flower>=2.0.1",
|
||||||
"gevent>=25.9.1",
|
"gevent>=25.9.1",
|
||||||
"granian>=2.5.5",
|
"granian>=2.5.5",
|
||||||
@@ -36,16 +36,16 @@ dependencies = [
|
|||||||
"jinja2>=3.1.6",
|
"jinja2>=3.1.6",
|
||||||
"loguru>=0.7.3",
|
"loguru>=0.7.3",
|
||||||
"msgspec>=0.19.0",
|
"msgspec>=0.19.0",
|
||||||
"psutil>=7.1.0",
|
"psutil>=7.1.1",
|
||||||
"psycopg[binary]>=3.2.10",
|
"psycopg[binary]>=3.2.10",
|
||||||
"pwdlib>=0.2.1",
|
"pwdlib>=0.2.1",
|
||||||
"pydantic>=2.12.1",
|
"pydantic>=2.12.3",
|
||||||
"pydantic-settings>=2.11.0",
|
"pydantic-settings>=2.11.0",
|
||||||
"pymysql>=1.1.2",
|
"pymysql>=1.1.2",
|
||||||
"python-jose>=3.5.0",
|
"python-jose>=3.5.0",
|
||||||
"python-socketio>=5.14.1",
|
"python-socketio>=5.14.2",
|
||||||
"redis[hiredis]>=6.4.0",
|
"redis[hiredis]>=6.4.0",
|
||||||
"rtoml>=0.12.0",
|
"rtoml>=0.13.0",
|
||||||
"sqlalchemy-crud-plus>=1.12.1",
|
"sqlalchemy-crud-plus>=1.12.1",
|
||||||
"sqlalchemy[asyncio]>=2.0.44",
|
"sqlalchemy[asyncio]>=2.0.44",
|
||||||
"sqlparse>=0.5.3",
|
"sqlparse>=0.5.3",
|
||||||
|
|||||||
+17
-17
@@ -69,13 +69,13 @@ colorama==0.4.6 ; sys_platform == 'win32'
|
|||||||
# loguru
|
# loguru
|
||||||
# pytest
|
# pytest
|
||||||
# uvicorn
|
# uvicorn
|
||||||
cryptography==46.0.2
|
cryptography==46.0.3
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
distlib==0.4.0
|
distlib==0.4.0
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
dnspython==2.8.0
|
dnspython==2.8.0
|
||||||
# via email-validator
|
# via email-validator
|
||||||
dulwich==0.24.3
|
dulwich==0.24.6
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
ecdsa==0.19.1
|
ecdsa==0.19.1
|
||||||
# via python-jose
|
# via python-jose
|
||||||
@@ -87,7 +87,7 @@ exceptiongroup==1.3.0 ; python_full_version < '3.11'
|
|||||||
# pytest
|
# pytest
|
||||||
fast-captcha==0.3.2
|
fast-captcha==0.3.2
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
fastapi==0.119.0
|
fastapi==0.119.1
|
||||||
# via
|
# via
|
||||||
# fastapi-best-architecture
|
# fastapi-best-architecture
|
||||||
# fastapi-limiter
|
# fastapi-limiter
|
||||||
@@ -115,7 +115,7 @@ h11==0.16.0
|
|||||||
# httpcore
|
# httpcore
|
||||||
# uvicorn
|
# uvicorn
|
||||||
# wsproto
|
# wsproto
|
||||||
hiredis==3.2.1
|
hiredis==3.3.0
|
||||||
# via redis
|
# via redis
|
||||||
httpcore==1.0.9
|
httpcore==1.0.9
|
||||||
# via httpx
|
# via httpx
|
||||||
@@ -123,7 +123,7 @@ httptools==0.7.1
|
|||||||
# via uvicorn
|
# via uvicorn
|
||||||
httpx==0.28.1
|
httpx==0.28.1
|
||||||
# via fastapi
|
# via fastapi
|
||||||
humanize==4.13.0
|
humanize==4.14.0
|
||||||
# via flower
|
# via flower
|
||||||
identify==2.6.15
|
identify==2.6.15
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
@@ -132,7 +132,7 @@ idna==3.11
|
|||||||
# anyio
|
# anyio
|
||||||
# email-validator
|
# email-validator
|
||||||
# httpx
|
# httpx
|
||||||
iniconfig==2.1.0
|
iniconfig==2.3.0
|
||||||
# via pytest
|
# via pytest
|
||||||
ip2loc==1.0.0
|
ip2loc==1.0.0
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
@@ -164,7 +164,7 @@ packaging==25.0
|
|||||||
# via
|
# via
|
||||||
# kombu
|
# kombu
|
||||||
# pytest
|
# pytest
|
||||||
pillow==11.3.0
|
pillow==12.0.0
|
||||||
# via fast-captcha
|
# via fast-captcha
|
||||||
platformdirs==4.5.0
|
platformdirs==4.5.0
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
@@ -175,11 +175,11 @@ prometheus-client==0.23.1
|
|||||||
# via flower
|
# via flower
|
||||||
prompt-toolkit==3.0.52
|
prompt-toolkit==3.0.52
|
||||||
# via click-repl
|
# via click-repl
|
||||||
psutil==7.1.0
|
psutil==7.1.1
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
psycopg==3.2.10
|
psycopg==3.2.11
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
psycopg-binary==3.2.10 ; implementation_name != 'pypy'
|
psycopg-binary==3.2.11 ; implementation_name != 'pypy'
|
||||||
# via psycopg
|
# via psycopg
|
||||||
pwdlib==0.2.1
|
pwdlib==0.2.1
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
@@ -189,14 +189,14 @@ pyasn1==0.6.1
|
|||||||
# rsa
|
# rsa
|
||||||
pycparser==2.23 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'
|
pycparser==2.23 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'
|
||||||
# via cffi
|
# via cffi
|
||||||
pydantic==2.12.1
|
pydantic==2.12.3
|
||||||
# via
|
# via
|
||||||
# fastapi
|
# fastapi
|
||||||
# fastapi-best-architecture
|
# fastapi-best-architecture
|
||||||
# fastapi-pagination
|
# fastapi-pagination
|
||||||
# pydantic-settings
|
# pydantic-settings
|
||||||
# sqlalchemy-crud-plus
|
# sqlalchemy-crud-plus
|
||||||
pydantic-core==2.41.3
|
pydantic-core==2.41.4
|
||||||
# via pydantic
|
# via pydantic
|
||||||
pydantic-settings==2.11.0
|
pydantic-settings==2.11.0
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
@@ -221,7 +221,7 @@ python-jose==3.5.0
|
|||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
python-multipart==0.0.20
|
python-multipart==0.0.20
|
||||||
# via fastapi
|
# via fastapi
|
||||||
python-socketio==5.14.1
|
python-socketio==5.14.2
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
pytz==2025.2
|
pytz==2025.2
|
||||||
# via flower
|
# via flower
|
||||||
@@ -242,7 +242,7 @@ rich-toolkit==0.15.1
|
|||||||
# via fastapi-cli
|
# via fastapi-cli
|
||||||
rsa==4.9.1
|
rsa==4.9.1
|
||||||
# via python-jose
|
# via python-jose
|
||||||
rtoml==0.12.0
|
rtoml==0.13.0
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
setuptools==80.9.0
|
setuptools==80.9.0
|
||||||
# via zope-event
|
# via zope-event
|
||||||
@@ -321,11 +321,11 @@ urllib3==2.5.0
|
|||||||
# via dulwich
|
# via dulwich
|
||||||
user-agents==2.2.0
|
user-agents==2.2.0
|
||||||
# via fastapi-best-architecture
|
# via fastapi-best-architecture
|
||||||
uvicorn==0.37.0
|
uvicorn==0.38.0
|
||||||
# via
|
# via
|
||||||
# fastapi
|
# fastapi
|
||||||
# fastapi-cli
|
# fastapi-cli
|
||||||
uvloop==0.21.0 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'
|
uvloop==0.22.1 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'
|
||||||
# via uvicorn
|
# via uvicorn
|
||||||
vine==5.1.0
|
vine==5.1.0
|
||||||
# via
|
# via
|
||||||
@@ -334,7 +334,7 @@ vine==5.1.0
|
|||||||
# kombu
|
# kombu
|
||||||
virtualenv==20.35.3
|
virtualenv==20.35.3
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
watchfiles==1.1.0
|
watchfiles==1.1.1
|
||||||
# via uvicorn
|
# via uvicorn
|
||||||
wcwidth==0.2.14
|
wcwidth==0.2.14
|
||||||
# via prompt-toolkit
|
# via prompt-toolkit
|
||||||
|
|||||||
Reference in New Issue
Block a user