最新技术栈
基于 FastAPI、SQLAlchemy 2.0、Pydantic-v2、Celery、等最新技术栈
diff --git a/404.html b/404.html new file mode 100644 index 0000000..e528bc0 --- /dev/null +++ b/404.html @@ -0,0 +1 @@ +
注意
默认端口冲突:8000,3306,6379,5672
建议在部署前关闭本地服务:mysql,redis,rabbitmq...
警告
部署 意味着你的所有代码已经准备就绪,可以用于生产,而本机部署则是为了能够快捷的提供本地 API 服务,所以,此教程仅提供 API 本机部署教程
env
进入 deploy/backend/docker-compose
目录,创建环境变量文件 .env
touch .env.server ../../../backend/.env
将初始化环境变量配置拷贝到环境变量文件中
cp .env.server ../../../backend/.env
按需修改配置文件 backend/core/conf.py
和 .env
执行一键启动命令
相关信息
命令执行期间遇到镜像拉取问题请自行 Google
docker-compose up -d --build
等待命令执行完成
提示
此教程以 https 为例,如果你没有相关经验,请自行 Google 进行了解
env
进入 deploy/backend/docker-compose
目录,创建环境变量文件 .env
touch .env.server ../../../backend/.env
将初始化环境变量配置拷贝到环境变量文件中
cp .env.server ../../../backend/.env
按需修改配置文件 backend/core/conf.py
和 .env
建议修改 .env
中的 ENVIRONMENT
为 pro
更新脚本文件
仓库内的 docker-compose.yml
文件默认为后端独立部署,如果你没有前端需求,而只需调用后端 API,请查看 本机部署
version: "3.10"
+
+networks:
+ fba_network:
+ name: fba_network
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.10.10.0/24
+
+volumes:
+ fba_mysql:
+ name: fba_mysql
+ fba_redis:
+ name: fba_redis
+ fba_static:
+ name: fba_static
+ fba_rabbitmq:
+ name: fba_rabbitmq
+
+services:
+ fba_server:
+ build:
+ context: ../../../
+ dockerfile: backend/backend.dockerfile
+ image: fba_server:latest
+ container_name: fba_server
+ restart: always
+ depends_on:
+ - fba_mysql
+ - fba_redis
+ - fba_celery
+ volumes:
+ - fba_static:/fba/backend/app/static
+ networks:
+ - fba_network
+ command:
+ - bash
+ - -c
+ - |
+ wait-for-it -s fba_mysql:3306 -s fba_redis:6379 -t 300
+ mkdir -p /var/log/supervisor/
+ supervisord -c /fba/deploy/backend/supervisor.conf
+ supervisorctl restart fastapi_server
+
+ fba_mysql:
+ image: mysql:8.0.29
+ ports:
+ - "\${DOCKER_MYSQL_MAP_PORT:-3306}:3306"
+ container_name: fba_mysql
+ restart: always
+ environment:
+ MYSQL_DATABASE: fba
+ MYSQL_ROOT_PASSWORD: 123456
+ TZ: Asia/Shanghai
+ volumes:
+ - fba_mysql:/var/lib/mysql
+ networks:
+ - 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:
+ image: redis:6.2.7
+ ports:
+ - "\${DOCKER_REDIS_MAP_PORT:-6379}:6379"
+ container_name: fba_redis
+ restart: always
+ environment:
+ - TZ=Asia/Shanghai
+ volumes:
+ - fba_redis:/var/lib/redis
+ networks:
+ - fba_network
+
+ # 后端专用,这与 fba_ui 冲突,如果你选择使用 fba_ui,
+ # 你应该注释或删除 fba_nginx 容器脚本,并使用 fba_ui 容器
+ fba_nginx:
+ image: nginx
+ ports:
+ - "8000:80"
+ container_name: fba_nginx
+ restart: always
+ depends_on:
+ - fba_server
+ volumes:
+ - ../nginx.conf:/etc/nginx/nginx.conf:ro
+ - fba_static:/www/fba_server/backend/static
+ networks:
+ - fba_network
+
+ # 如果服务器内存小于 4GB,CPU 小于四个内核
+ # 建议进入 fba_ui 项目单独构建这个容器(参考下方前端部署教程)
+ # 如果你不选择单独构建,务必在执行下面步骤前根据前端部署教程更新前端配置文件
+ # 如果你选择单独构建,务必注释或删除此容器脚本
+ fba_ui:
+ build:
+ context: /root/fastapi_best_architecture_ui # 根据 fba_ui 项目存放目录修改此路径
+ dockerfile: Dockerfile
+ image: fba_ui:latest
+ ports:
+ - "80:80"
+ - "443:443"
+ container_name: fba_ui
+ restart: always
+ depends_on:
+ - fba_server
+ command:
+ - nginx
+ - -g
+ - daemon off;
+ volumes:
+ # nginx https conf
+ # 通过 docker 进行部署时,需要打开此配置项并确保<挂载到容器内的证书文件路径>配置
+ # 与 nginx conf 中的 ssl 证书文件路径配置一致,如果你直接将 ssl 证书文件 cp
+ # 到了 docker 容器内,则无需挂载证书文件,直接将它们注释或删除即可
+ # local_ssl_pem_path:你在服务器存放 ssl pem 证书文件的路径,自行修改
+ # local_ssl_key_path: 你在服务器存放 ssl key 证书文件的路径,自行修改
+ # /etc/ssl/xxx.pem:挂载到容器内 ssl pem 证书文件的路径,自行修改
+ # /etc/ssl/xxx.key:挂载到容器内 ssl key 证书文件的路径,自行修改
+ - local_ssl_pem_path:/etc/ssl/xxx.pem
+ - local_ssl_key_path:/etc/ssl/xxx.key
+ - fba_static:/www/fba_server/backend/static
+ networks:
+ - fba_network
+
+ fba_rabbitmq:
+ hostname: fba_rabbitmq
+ image: rabbitmq:3.12.7
+ ports:
+ - "15672:15672"
+ - "5672:5672"
+ container_name: fba_rabbitmq
+ restart: always
+ environment:
+ - RABBITMQ_DEFAULT_USER=guest
+ - RABBITMQ_DEFAULT_PASS=guest
+ volumes:
+ - fba_rabbitmq:/var/lib/rabbitmq
+ networks:
+ - fba_network
+
+ fba_celery:
+ build:
+ context: ../../../
+ dockerfile: backend/celery.dockerfile
+ image: fba_celery:latest
+ ports:
+ - "8555:8555"
+ container_name: fba_celery
+ restart: always
+ depends_on:
+ - fba_rabbitmq
+ networks:
+ - fba_network
+ command:
+ - bash
+ - -c
+ - |
+ wait-for-it -s fba_rabbitmq:5672 -t 300
+ mkdir -p /var/log/supervisor/
+ supervisord -c /fba/deploy/backend/supervisor.conf
+ supervisorctl restart celery_worker
+ supervisorctl restart celery_beat
+ supervisorctl restart celery_flower
执行一键启动命令
相关信息
命令执行期间遇到镜像拉取问题请自行 Google
docker-compose up -d --build
等待命令执行完成
警告
我们提供此前端部署教程的目的是为你提供前端 Docker 部署解决方案,请记住我们的声明,此前端项目仅作为效果演示,而不是用于生产!
拉取代码到服务器
env
修改 .env.production
中的 VITE_API_BASE_URL
为域名地址
更新 nginx
进入 deploy 目录,编辑 nginx.conf 文件
# For more information on configuration, see:
+# * Official English Documentation: http://nginx.org/en/docs/
+# * Official Russian Documentation: http://nginx.org/ru/docs/
+
+worker_processes auto;
+error_log /var/log/nginx/error.log;
+pid /run/nginx.pid;
+
+# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
+include /usr/share/nginx/modules/*.conf;
+
+events {
+worker_connections 1024;
+}
+
+http {
+
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ sendfile on;
+ client_max_body_size 5M;
+ client_body_buffer_size 5M;
+
+ gzip on;
+ gzip_comp_level 2;
+ gzip_types text/plain text/css text/javascript application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png;
+ gzip_vary on;
+
+ keepalive_timeout 300;
+
+ server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+ server_name 127.0.0.1;
+
+ listen 443 ssl;
+ # docker ssl 证书文件路径配置应该与 docker-compose 中的保持一致
+ # /etc/ssl/xxx.pem:挂载到容器内 ssl pem 证书文件的路径,自行修改
+ # /etc/ssl/xxx.key:挂载到容器内 ssl key 证书文件的路径,自行修改
+ ssl_certificate /etc/ssl/xxx.pem;
+ ssl_certificate_key /etc/ssl/xxx.key;
+ ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_prefer_server_ciphers on;
+
+ # xxx.com 应该与 .env.production 中的配置保持一致
+ server_name xxx.com;
+
+ client_max_body_size 10m;
+
+ root /www/fba_ui;
+
+ location / {
+ try_files $uri $uri/ /index.html;
+ }
+
+ location /api/v1/ {
+ proxy_pass http://fba_server:8001;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_connect_timeout 300s;
+ proxy_send_timeout 300s;
+ proxy_read_timeout 300s;
+ }
+
+ location /static/ {
+ alias /www/fba_server/backend/static;
+ }
+ }
+
+ server {
+ listen 80;
+ # xxx.com 应该与 .env.production 中的配置保持一致
+ server_name xxx.com;
+ rewrite ^(.*)$ https://$host$1 permanent;
+ }
+}
更新脚本文件
注意
如果已通过后端 docker-compose 构建前端项目,此步骤和后面的剩余步骤直接跳过即可
networks:
+ fba_network:
+ external: true
+
+volumes:
+ fba_static:
+ external: true
+
+services:
+ fba_ui:
+ build:
+ context: ../
+ dockerfile: Dockerfile
+ image: fba_ui:latest
+ ports:
+ - "80:80"
+ - "443:443"
+ container_name: fba_ui
+ restart: always
+ command:
+ - nginx
+ - -g
+ - daemon off;
+ volumes:
+ # nginx https conf
+ # 通过 docker 进行部署时,需要打开此配置项并确保<挂载到容器内的证书文件路径>配置
+ # 与 nginx conf 中的 ssl 证书文件路径配置一致,如果你直接将 ssl 证书文件 cp
+ # 到了 docker 容器内,则无需挂载证书文件,直接将它们注释或删除即可
+ # local_ssl_pem_path:你在服务器存放 ssl pem 证书文件的路径,自行修改
+ # local_ssl_key_path: 你在服务器存放 ssl key 证书文件的路径,自行修改
+ # /etc/ssl/xxx.pem:挂载到容器内 ssl pem 证书文件的路径,自行修改
+ # /etc/ssl/xxx.key:挂载到容器内 ssl key 证书文件的路径,自行修改
+ - local_ssl_pem_path:/etc/ssl/xxx.pem
+ - local_ssl_key_path:/etc/ssl/xxx.key
+ - fba_static:/www/fba_server/backend/static
+ networks:
+ - fba_network
构建并启动容器
创建网络
docker network create fba_network
构建
docker-compose build fba_ui
启动
docker-compose run fba_ui
注意
请不要频繁使用 docker-compose up -d --build
命令,每次执行,此命令都会构建容器,并将原容器自动进行本地备份保留,这会导致硬盘空间迅速递减
清理未使用的镜像
docker image prune
清理未使用的容器
docker container prune
清理所有未使用的镜像、容器、网络和构建缓存
docker system prune
清理所有悬空的镜像和卷
docker system prune -a --volumes
当进行前后端项目联调或服务器部署时,你通常会遇到跨域问题,不过没关系,你只需修改后端配置,就可以轻松解决 CORS 相关问题
进入 core/conf.py
文件,修改 CORS_ALLOWED_ORIGINS
配置即可
CORS_ALLOWED_ORIGINS: list[str] = [
+ 'http://localhost:5173', # 前端访问地址,末尾不要带 '/'
+ ]
进入 core/conf.py
文件,修改 CORS_ALLOWED_ORIGINS
配置即可
非 https 部署
CORS_ALLOWED_ORIGINS: list[str] = [
+ 'http://服务器ip:端口号', # 前端访问地址,末尾不要带 '/'
+ ]
https 部署
CORS_ALLOWED_ORIGINS: list[str] = [
+ 'https://域名', # 前端访问地址,末尾不要带 '/'
+ ]
提示
此仓库作为模板库公开,任何人或企业均可免费使用!
🔥持续更新维护中🔥
mvc 架构作为常规设计模式,在 python web 中也很常见,但是三层架构更令人着迷
在 python web 开发中,三层架构的概念并没有通用标准,所以这里我们称之为伪三层架构
但请注意,我们并没有传统的多应用程序结构(django、springBoot...),如果您不喜欢这种模式,可以使用模板对其进行随意改造!
工作流程 | java | fastapi_best_architecture |
---|---|---|
视图 | controller | api |
数据传输 | dto | schema |
业务逻辑 | service + impl | service |
数据访问 | dao / mapper | crud |
模型 | model / entity | model |
本项目由 MIT 许可证的条款进行许可
TODO
RBAC 提供了两种解决方案,第一种【角色菜单】可能更加常见,它可以设置按钮级别的控制规则,另外一种是【Casbin】,它非常灵活,可以通过模型定义多种 控制规则(我认为它很好,性能也很出色),这种设计在 Go 语言中应用更加广泛, 我们在最初架构设计时,参考了 go-admin,gin-vue-admin... 等优秀 的开源项目,同时引入了 Casbin,它在众多 python web 开源项目中可能是极为罕见的,并且,它的学习成本相对较高,如果你对此感兴趣,可以通过 Casbin 官网 进行学习,另外,这两个视频教程 ( 半小时彻底弄懂Casbin基础模型、 Casbin的代码使用、api调用、自定义比较方法 ) 可能起到画龙点睛之笔
TODO
TODO
',8)]))}const d=a(n,[["render",s],["__file","permission.html.vue"]]),l=JSON.parse(`{"path":"/guide/reference/permission.html","title":"权限","lang":"zh-CN","frontmatter":{"title":"权限","createTime":"2024/09/16 22:48:13","head":[["script",{"id":"check-dark-mode"},";(function () {const um= localStorage.getItem('vuepress-theme-appearance') || 'auto';const sm = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;if (um === 'dark' || (um !== 'light' && sm)) {document.documentElement.classList.add('dark');}})();"],["script",{"id":"check-mac-os"},"document.documentElement.classList.toggle('mac', /Mac|iPhone|iPod|iPad/i.test(navigator.platform))"]]},"headers":[{"level":2,"title":"JWT","slug":"jwt","link":"#jwt","children":[]},{"level":2,"title":"RBAC","slug":"rbac","link":"#rbac","children":[{"level":3,"title":"角色菜单","slug":"角色菜单","link":"#角色菜单","children":[]},{"level":3,"title":"Casbin","slug":"casbin","link":"#casbin","children":[]}]}],"readingTime":{"minutes":0.84,"words":251},"git":{"createdTime":1726501588000,"updatedTime":1726984104000,"contributors":[{"name":"Wu Clan","email":"jianhengwu0407@gmail.com","commits":2}]},"filePathRelative":"guide/reference/permission.md","categoryList":[{"id":"a0c391","sort":10000,"name":"guide"},{"id":"011963","sort":10002,"name":"reference"}]}`);export{d as comp,l as data}; diff --git a/assets/photoswipe.esm-GXRgw7eJ.js b/assets/photoswipe.esm-GXRgw7eJ.js new file mode 100644 index 0000000..2fd7cfd --- /dev/null +++ b/assets/photoswipe.esm-GXRgw7eJ.js @@ -0,0 +1,4 @@ +/*! + * PhotoSwipe 5.4.4 - https://photoswipe.com + * (c) 2024 Dmytro Semenov + */function f(r,t,i){const e=document.createElement(t);return r&&(e.className=r),i&&i.appendChild(e),e}function p(r,t){return r.x=t.x,r.y=t.y,t.id!==void 0&&(r.id=t.id),r}function M(r){r.x=Math.round(r.x),r.y=Math.round(r.y)}function A(r,t){const i=Math.abs(r.x-t.x),e=Math.abs(r.y-t.y);return Math.sqrt(i*i+e*e)}function x(r,t){return r.x===t.x&&r.y===t.y}function I(r,t,i){return Math.min(Math.max(r,t),i)}function b(r,t,i){let e=`translate3d(${r}px,${t||0}px,0)`;return i!==void 0&&(e+=` scale3d(${i},${i},1)`),e}function y(r,t,i,e){r.style.transform=b(t,i,e)}const $="cubic-bezier(.4,0,.22,1)";function R(r,t,i,e){r.style.transition=t?`${t} ${i}ms ${e||$}`:"none"}function L(r,t,i){r.style.width=typeof t=="number"?`${t}px`:t,r.style.height=typeof i=="number"?`${i}px`:i}function U(r){R(r)}function q(r){return"decode"in r?r.decode().catch(()=>{}):r.complete?Promise.resolve(r):new Promise((t,i)=>{r.onload=()=>t(r),r.onerror=i})}const _={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function G(r){return"button"in r&&r.button===1||r.ctrlKey||r.metaKey||r.altKey||r.shiftKey}function K(r,t,i=document){let e=[];if(r instanceof Element)e=[r];else if(r instanceof NodeList||Array.isArray(r))e=Array.from(r);else{const s=typeof r=="string"?r:t;s&&(e=Array.from(i.querySelectorAll(s)))}return e}function C(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}let F=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{F=!0}}))}catch{}class X{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach(t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)}),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;const a=n?"removeEventListener":"addEventListener";i.split(" ").forEach(l=>{if(l){o||(n?this._pool=this._pool.filter(d=>d.type!==l||d.listener!==e||d.target!==t):this._pool.push({target:t,type:l,listener:e,passive:s}));const c=F?{passive:s||!1}:!1;t[a](l,e,c)}})}}function B(r,t){if(r.getViewportSizeFn){const i=r.getViewportSizeFn(r,t);if(i)return i}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function S(r,t,i,e,s){let n=0;if(t.paddingFn)n=t.paddingFn(i,e,s)[r];else if(t.padding)n=t.padding[r];else{const o="padding"+r[0].toUpperCase()+r.slice(1);t[o]&&(n=t[o])}return Number(n)||0}function N(r,t,i,e){return{x:t.x-S("left",r,t,i,e)-S("right",r,t,i,e),y:t.y-S("top",r,t,i,e)-S("bottom",r,t,i,e)}}class Y{constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){const{pswp:i}=this.slide,e=this.slide[t==="x"?"width":"height"]*this.currZoomLevel,n=S(t==="x"?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),o=this.slide.panAreaSize[t];this.center[t]=Math.round((o-e)/2)+n,this.max[t]=e>o?Math.round(o-e)+n:this.center[t],this.min[t]=e>o?n:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return I(i,this.max[t],this.min[t])}}const T=4e3;class H{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){const s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;const n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,n重要
请一字不落的认真对待此文档,并严格按照本文档的顺序启动项目,否则你有很大几率在启动过程中遇到各种问题
准备本地环境
准备 Git 仓库
相关信息
提供两种方案,选择其中一种即可
拉取源代码仓库
此方式需要你删除拉取项目后根目录下的 .git
文件夹,之后上传到你指定的仓库即可,具体请自行查阅你要上传平台的行为准则
git clone https://github.com/fastapi-practices/fastapi_best_architecture.git
拉取模板仓库
此项目支持创建模板仓库,意味着,你可以直接创建一个非 fork(独立无绑定的关系)的个人账户仓库,如果所示,进入此项目 GitHub 首页, 使用 use this template
按钮创建即可,创建完成之后,使用 git clone
命令拉取你自己的仓库即可
安装依赖包
拉取项目到本地后,进入项目 backend
目录,执行以下命令
pip install -r requirements.txt
创建一个数据库:fba
,选择 utf8mb4 编码
启动 Redis
env
在 backend
目录中,创建环境变量文件
touch .env
将初始化环境变量配置拷贝到环境变量文件中
cp .env.example .env
按需修改配置文件 core/conf.py
和 .env
相关信息
默认情况下,首次启动不需要修改
数据库迁移 alembic
生成迁移文件
alembic revision --autogenerate
执行迁移
alembic upgrade head
启动 celery worker, beat 和 flower (可选)
Celery 应用程序
celery -A app.task.celery worker -l info
定时任务
celery -A app.task.celery beat -l info
web 监控
celery -A app.task.celery flower --port=8555 --basic-auth=admin:123456
初始化测试数据
使用 backend/sql/init_test_data.sql
文件初始化测试数据
启动 fastapi 服务
此项目采用 fastapi CLI 应用启动服务,当前,为了方便本地调试,你仍然可以选择使用 pycharm 右键运行 main.py
文件
帮助
fastapi --help
开发模式
fastapi dev main.py
准备本地环境
安装和启动
警告
目前它仅作为效果演示,而不是用于生产!
如果你不想前端依赖安装问题带来困扰,请务必使用 yarn
v1.x 版本
你可以跳转 fastapi_best_architecture_ui 查看详情
相关信息
仅供参考,实际以个人为准
定义数据库模型(model)
定义数据验证模型(schema)
定义视图(api)和路由(router)
编写业务(service)
编写数据库操作(crud)
相关信息
通过 pytest
运行单元测试,项目内仅提供了非常简易的 demo,并不是完整单元测试,如需要,请自行编写
创建测试数据库 fba_test
,选择 utf8mb4 编码
使用 backend/sql/create_tables.sql
文件创建数据库表
使用 backend/sql/init_pytest_data.sql
文件初始化用于单元测试的测试数据
进入 backend
目录,执行单元测试命令
pytest -vs --disable-warnings
写在前面
我们不会去和其他架构做比较,我们认为每个架构都有自己的特点,适合不同的场景。
我们的目标是提供一个最佳架构,让开发者可以快速上手,专注于业务逻辑的开发,所以我们只会不断完善和优化我们的架构,为开发者更好的体验。
重要
如果你缺乏资深的后端开发经验,目前的代码架构可能并不适合你,因为其中已经集成了相当复杂的功能实现。 我们建议新手用户从一些基础和简单的内容入手,这不仅是对自身学习的负责态度,也为将来能够顺利掌握这一架构奠定坚实的基础
无任何强制收费行为,我们唯一的收入来源仅为赞助,它们将全部用于基础设施建设(服务器,域名...)
如果您的网站与 FastAPI Best Architecture 相关,或者也属于开源项目(无知识星球付费内容,无授权相关内容),欢迎与我们联系
Kinit Fast Task 为 FastAPI 项目脚手架,高性能,高效率,易扩展,长期维护,积极更新!
基于 FastAPI、SQLAlchemy 2.0、Pydantic-v2、Celery、等最新技术栈
独特的「伪三层架构」,让所有开发者轻松驾驭
基于 async/await + asgiref 实现全局异步处理,告别协程阻塞问题
提供后端代码自动生成,告别繁琐基础代码结构 cv
提供 Casbin、Role-Menu 两种 RBAC 权限方案。开关控制选择
带有缓存和白名单的 JWT 中间件自动认证
提供 Docker compose 一键部署方案
通过配置一键应用全局时区时间,告别时间处理烦恼
内置十分强大的日志系统,全方位 Trace ID 助你一步锁定问题