Skip to content

Commit f846f40

Browse files
committed
Optimize core、middleware、database、utils...
1 parent 742988e commit f846f40

31 files changed

+531
-367
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.idea/
22
.vscode/
3+
.cursor/
34
.DS_Store
45
venv/
56
.venv/

backend/app/admin/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
from pydantic_settings import BaseSettings, SettingsConfigDict
66

7-
from backend.core.path_conf import BasePath
7+
from backend.core.path_conf import BASE_PATH
88

99

1010
class AdminSettings(BaseSettings):
1111
"""Admin Settings"""
1212

13-
model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore')
13+
model_config = SettingsConfigDict(env_file=f'{BASE_PATH}/.env', env_file_encoding='utf-8', extra='ignore')
1414

1515
# OAuth2:https://github.com/fastapi-practices/fastapi_oauth20
1616
# GitHub

backend/app/admin/crud/crud_user.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ async def get_list(self, dept: int = None, username: str = None, phone: str = No
191191
)
192192
.order_by(desc(self.model.join_time))
193193
)
194-
194+
195195
# 构建过滤条件
196196
filters = []
197197
if dept:
@@ -202,11 +202,11 @@ async def get_list(self, dept: int = None, username: str = None, phone: str = No
202202
filters.append(self.model.phone.like(f'%{phone}%'))
203203
if status is not None:
204204
filters.append(self.model.status == status)
205-
205+
206206
# 应用过滤条件
207207
if filters:
208208
stmt = stmt.where(and_(*filters))
209-
209+
210210
return stmt
211211

212212
async def get_super(self, db: AsyncSession, user_id: int) -> bool:

backend/app/generator/service/gen_service.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from backend.app.generator.schema.gen_model import CreateGenModelParam
2121
from backend.app.generator.service.gen_model_service import gen_model_service
2222
from backend.common.exception import errors
23-
from backend.core.path_conf import BasePath
23+
from backend.core.path_conf import BASE_PATH
2424
from backend.database.db import async_db_session
2525
from backend.utils.gen_template import gen_template
2626
from backend.utils.type_conversion import sql_type_to_pydantic
@@ -114,7 +114,7 @@ async def generate(self, *, pk: int) -> None:
114114
tpl_code_map = await self.render_tpl_code(business=business)
115115
gen_path = business.gen_path
116116
if not gen_path:
117-
gen_path = os.path.join(BasePath, 'app')
117+
gen_path = os.path.join(BASE_PATH, 'app')
118118
for tpl_path, code in tpl_code_map.items():
119119
code_filepath = os.path.join(
120120
gen_path,

backend/app/task/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from pydantic import model_validator
88
from pydantic_settings import BaseSettings, SettingsConfigDict
99

10-
from backend.core.path_conf import BasePath
10+
from backend.core.path_conf import BASE_PATH
1111

1212

1313
class TaskSettings(BaseSettings):
1414
"""Task Settings"""
1515

16-
model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore')
16+
model_config = SettingsConfigDict(env_file=f'{BASE_PATH}/.env', env_file_encoding='utf-8', extra='ignore')
1717

1818
# Env Config
1919
ENVIRONMENT: Literal['dev', 'pro']

backend/core/conf.py

+73-74
Original file line numberDiff line numberDiff line change
@@ -6,97 +6,97 @@
66
from pydantic import model_validator
77
from pydantic_settings import BaseSettings, SettingsConfigDict
88

9-
from backend.core.path_conf import BasePath
9+
from backend.core.path_conf import BASE_PATH
1010

1111

1212
class Settings(BaseSettings):
13-
"""Global Settings"""
13+
"""全局配置"""
1414

15-
model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore')
15+
model_config = SettingsConfigDict(
16+
env_file=f'{BASE_PATH}/.env', env_file_encoding='utf-8', extra='ignore', case_sensitive=True
17+
)
1618

17-
# Env Config
19+
# 环境配置(从环境变量读取)
1820
ENVIRONMENT: Literal['dev', 'pro']
1921

20-
# Env Database Type
22+
# 数据库配置(从环境变量读取)
2123
DATABASE_TYPE: Literal['mysql', 'postgresql']
22-
23-
# Env Database
2424
DATABASE_HOST: str
2525
DATABASE_PORT: int
2626
DATABASE_USER: str
2727
DATABASE_PASSWORD: str
2828

29-
# Env Redis
29+
# Redis 配置(从环境变量读取)
3030
REDIS_HOST: str
3131
REDIS_PORT: int
3232
REDIS_PASSWORD: str
3333
REDIS_DATABASE: int
3434

35-
# Env Token
35+
# Token 配置(从环境变量读取)
3636
TOKEN_SECRET_KEY: str # 密钥 secrets.token_urlsafe(32)
3737

38-
# Env Opera Log
38+
# 操作日志加密密钥(从环境变量读取)
3939
OPERA_LOG_ENCRYPT_SECRET_KEY: str # 密钥 os.urandom(32), 需使用 bytes.hex() 方法转换为 str
4040

41-
# FastAPI
42-
FASTAPI_API_V1_PATH: str = '/api/v1'
43-
FASTAPI_TITLE: str = 'FastAPI'
44-
FASTAPI_VERSION: str = '0.0.1'
45-
FASTAPI_DESCRIPTION: str = 'FastAPI Best Architecture'
46-
FASTAPI_DOCS_URL: str = '/docs'
47-
FASTAPI_REDOC_URL: str = '/redoc'
48-
FASTAPI_OPENAPI_URL: str | None = '/openapi'
49-
FASTAPI_STATIC_FILES: bool = True
50-
51-
# Upload
52-
UPLOAD_READ_SIZE: int = 1024 # 上传文件时分片读取大小
53-
UPLOAD_IMAGE_EXT_INCLUDE: list[str] = ['jpg', 'jpeg', 'png', 'gif', 'webp']
54-
UPLOAD_IMAGE_SIZE_MAX: int = 1024 * 1024 * 5
55-
UPLOAD_VIDEO_EXT_INCLUDE: list[str] = ['mp4', 'mov', 'avi', 'flv']
56-
UPLOAD_VIDEO_SIZE_MAX: int = 1024 * 1024 * 20
57-
58-
# Database
41+
# 数据库配置(默认值)
5942
DATABASE_ECHO: bool = False
6043
DATABASE_POOL_ECHO: bool = False
6144
DATABASE_SCHEMA: str = 'fba'
6245
DATABASE_CHARSET: str = 'utf8mb4'
6346

64-
# Redis
47+
# Redis 配置(默认值)
6548
REDIS_TIMEOUT: int = 5
6649

67-
# Socketio
68-
WS_NO_AUTH_MARKER: str = 'internal'
69-
70-
# Token
71-
TOKEN_ALGORITHM: str = 'HS256' # 算法
72-
TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
73-
TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # refresh token 过期时间,单位:秒
50+
# Token 配置(默认值)
51+
TOKEN_ALGORITHM: str = 'HS256'
52+
TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 # 1 天
53+
TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 7 天
7454
TOKEN_REDIS_PREFIX: str = 'fba:token'
7555
TOKEN_EXTRA_INFO_REDIS_PREFIX: str = 'fba:token_extra_info'
7656
TOKEN_ONLINE_REDIS_PREFIX: str = 'fba:token_online'
7757
TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:refresh_token'
78-
TOKEN_REQUEST_PATH_EXCLUDE: list[str] = [ # JWT / RBAC 白名单
79-
f'{FASTAPI_API_V1_PATH}/auth/login',
58+
TOKEN_REQUEST_PATH_EXCLUDE: list[str] = [ # JWT / RBAC 路由白名单
59+
'/api/v1/auth/login',
8060
]
8161

82-
# JWT
62+
# JWT 配置(默认值)
8363
JWT_USER_REDIS_PREFIX: str = 'fba:user'
84-
JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
64+
JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 7 天
8565

86-
# RBAC
66+
# RBAC 配置(默认值)
8767
RBAC_ROLE_MENU_MODE: bool = False
8868
RBAC_ROLE_MENU_EXCLUDE: list[str] = [
8969
'sys:monitor:redis',
9070
'sys:monitor:server',
9171
]
9272

93-
# Cookies
73+
# Cookie 配置(默认值)
9474
COOKIE_REFRESH_TOKEN_KEY: str = 'fba_refresh_token'
95-
COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS: int = TOKEN_REFRESH_EXPIRE_SECONDS
75+
COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 7 天
76+
77+
# FastAPI 配置(默认值)
78+
FASTAPI_API_V1_PATH: str = '/api/v1'
79+
FASTAPI_TITLE: str = 'FastAPI'
80+
FASTAPI_VERSION: str = '0.0.1'
81+
FASTAPI_DESCRIPTION: str = 'FastAPI Best Architecture'
82+
FASTAPI_DOCS_URL: str = '/docs'
83+
FASTAPI_REDOC_URL: str = '/redoc'
84+
FASTAPI_OPENAPI_URL: str | None = '/openapi'
85+
FASTAPI_STATIC_FILES: bool = True
86+
87+
# Socketio 配置(默认值)
88+
WS_NO_AUTH_MARKER: str = 'internal'
89+
90+
# 文件上传配置(默认值)
91+
UPLOAD_READ_SIZE: int = 1024
92+
UPLOAD_IMAGE_EXT_INCLUDE: list[str] = ['jpg', 'jpeg', 'png', 'gif', 'webp']
93+
UPLOAD_IMAGE_SIZE_MAX: int = 5 * 1024 * 1024 # 5 MB
94+
UPLOAD_VIDEO_EXT_INCLUDE: list[str] = ['mp4', 'mov', 'avi', 'flv']
95+
UPLOAD_VIDEO_SIZE_MAX: int = 20 * 1024 * 1024 # 20 MB
9696

97-
# Log
97+
# 日志配置(默认值)
9898
LOG_CID_DEFAULT_VALUE: str = '-'
99-
LOG_CID_UUID_LENGTH: int = 32 # must <= 32
99+
LOG_CID_UUID_LENGTH: int = 32 # 日志 correlation_id 长度,必须小于等于 32
100100
LOG_STD_LEVEL: str = 'INFO'
101101
LOG_ACCESS_FILE_LEVEL: str = 'INFO'
102102
LOG_ERROR_FILE_LEVEL: str = 'ERROR'
@@ -111,51 +111,51 @@ class Settings(BaseSettings):
111111
LOG_ACCESS_FILENAME: str = 'fba_access.log'
112112
LOG_ERROR_FILENAME: str = 'fba_error.log'
113113

114-
# Middleware
114+
# 中间件配置(默认值)
115115
MIDDLEWARE_CORS: bool = True
116116
MIDDLEWARE_ACCESS: bool = True
117117

118-
# Trace ID
118+
# 追踪 ID 配置(默认值)
119119
TRACE_ID_REQUEST_HEADER_KEY: str = 'X-Request-ID'
120120

121-
# CORS
122-
CORS_ALLOWED_ORIGINS: list[str] = [
121+
# CORS 配置(默认值)
122+
CORS_ALLOWED_ORIGINS: list[str] = [ # 末尾不带斜杠
123123
'http://127.0.0.1:8000',
124-
'http://localhost:5173', # 前端地址,末尾不要带 '/'
124+
'http://localhost:5173',
125125
]
126126
CORS_EXPOSE_HEADERS: list[str] = [
127-
TRACE_ID_REQUEST_HEADER_KEY,
127+
'X-Request-ID',
128128
]
129129

130-
# DateTime
130+
# 时间配置(默认值)
131131
DATETIME_TIMEZONE: str = 'Asia/Shanghai'
132132
DATETIME_FORMAT: str = '%Y-%m-%d %H:%M:%S'
133133

134-
# Request limiter
134+
# 请求限制配置(默认值)
135135
REQUEST_LIMITER_REDIS_PREFIX: str = 'fba:limiter'
136136

137-
# Demo mode (Only GET, OPTIONS requests are allowed)
137+
# 演示模式配置(默认值)
138138
DEMO_MODE: bool = False
139139
DEMO_MODE_EXCLUDE: set[tuple[str, str]] = {
140-
('POST', f'{FASTAPI_API_V1_PATH}/auth/login'),
141-
('POST', f'{FASTAPI_API_V1_PATH}/auth/logout'),
142-
('GET', f'{FASTAPI_API_V1_PATH}/auth/captcha'),
140+
('POST', '/api/v1/auth/login'),
141+
('POST', '/api/v1/auth/logout'),
142+
('GET', '/api/v1/auth/captcha'),
143143
}
144144

145-
# Ip location
145+
# IP 定位配置(默认值)
146146
IP_LOCATION_PARSE: Literal['online', 'offline', 'false'] = 'offline'
147147
IP_LOCATION_REDIS_PREFIX: str = 'fba:ip:location'
148-
IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
148+
IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 # 1 天
149149

150-
# Opera log
150+
# 操作日志配置(默认值)
151151
OPERA_LOG_PATH_EXCLUDE: list[str] = [
152152
'/favicon.ico',
153-
FASTAPI_DOCS_URL,
154-
FASTAPI_REDOC_URL,
155-
FASTAPI_OPENAPI_URL,
156-
f'{FASTAPI_API_V1_PATH}/auth/login/swagger',
157-
f'{FASTAPI_API_V1_PATH}/oauth2/github/callback',
158-
f'{FASTAPI_API_V1_PATH}/oauth2/linux-do/callback',
153+
'/docs',
154+
'/redoc',
155+
'/openapi',
156+
'/api/v1/auth/login/swagger',
157+
'/api/v1/oauth2/github/callback',
158+
'/api/v1/oauth2/linux-do/callback',
159159
]
160160
OPERA_LOG_ENCRYPT_TYPE: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ******
161161
OPERA_LOG_ENCRYPT_KEY_INCLUDE: list[str] = [ # 将加密接口入参参数对应的值
@@ -165,10 +165,8 @@ class Settings(BaseSettings):
165165
'confirm_password',
166166
]
167167

168-
# Data permission
169-
DATA_PERMISSION_MODELS: dict[
170-
str, str
171-
] = { # 允许进行数据过滤的 SQLA 模型,它必须以模块字符串的方式定义(它应该只用于前台数据,这里只是为了演示)
168+
# 数据权限配置(默认值)
169+
DATA_PERMISSION_MODELS: dict[str, str] = { # 允许进行数据过滤的 SQLA 模型,它必须以模块字符串的方式定义
172170
'Api': 'backend.plugin.casbin.model.Api',
173171
}
174172
DATA_PERMISSION_COLUMN_EXCLUDE: list[str] = [ # 排除允许进行数据过滤的 SQLA 模型列
@@ -178,24 +176,25 @@ class Settings(BaseSettings):
178176
'updated_time',
179177
]
180178

181-
# Plugin
179+
# 插件配置(默认值)
182180
PLUGIN_PIP_CHINA: bool = True
183181
PLUGIN_PIP_INDEX_URL: str = 'https://mirrors.aliyun.com/pypi/simple/'
184182

185183
@model_validator(mode='before')
186184
@classmethod
187185
def check_env(cls, values: Any) -> Any:
188-
if values['ENVIRONMENT'] == 'pro':
186+
"""生产环境下禁用 OpenAPI 文档和静态文件服务"""
187+
if values.get('ENVIRONMENT') == 'pro':
189188
values['FASTAPI_OPENAPI_URL'] = None
190189
values['FASTAPI_STATIC_FILES'] = False
191190
return values
192191

193192

194193
@lru_cache
195194
def get_settings() -> Settings:
196-
"""获取全局配置"""
195+
"""获取全局配置单例"""
197196
return Settings()
198197

199198

200-
# 创建配置实例
199+
# 创建全局配置实例
201200
settings = get_settings()

backend/core/path_conf.py

+11-14
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
import os
4-
53
from pathlib import Path
64

7-
# 获取项目根目录
8-
# 或使用绝对路径,指到backend目录为止,例如windows:BasePath = D:\git_project\fastapi_mysql\backend
9-
BasePath = Path(__file__).resolve().parent.parent
5+
# 项目根目录
6+
BASE_PATH = Path(__file__).resolve().parent.parent
107

118
# alembic 迁移文件存放路径
12-
ALEMBIC_VERSION_DIR = os.path.join(BasePath, 'alembic', 'versions')
9+
ALEMBIC_VERSION_DIR = BASE_PATH / 'alembic' / 'versions'
1310

1411
# 日志文件路径
15-
LOG_DIR = os.path.join(BasePath, 'log')
16-
17-
# 离线 IP 数据库路径
18-
IP2REGION_XDB = os.path.join(BasePath, 'static', 'ip2region.xdb')
12+
LOG_DIR = BASE_PATH / 'log'
1913

2014
# 静态资源目录
21-
STATIC_DIR = os.path.join(BasePath, 'static')
15+
STATIC_DIR = BASE_PATH / 'static'
2216

2317
# 上传文件目录
24-
UPLOAD_DIR = os.path.join(BasePath, 'static', 'upload')
18+
UPLOAD_DIR = STATIC_DIR / 'upload'
2519

2620
# jinja2 模版文件路径
27-
JINJA2_TEMPLATE_DIR = os.path.join(BasePath, 'templates')
21+
JINJA2_TEMPLATE_DIR = BASE_PATH / 'templates'
2822

2923
# 插件目录
30-
PLUGIN_DIR = os.path.join(BasePath, 'plugin')
24+
PLUGIN_DIR = BASE_PATH / 'plugin'
25+
26+
# 离线 IP 数据库路径
27+
IP2REGION_XDB = STATIC_DIR / 'ip2region.xdb'

0 commit comments

Comments
 (0)