修复scalar_one_or_none相关limit

This commit is contained in:
2026-06-03 14:15:21 +08:00
parent 446450c7d2
commit 8f27794da6
24 changed files with 73 additions and 52 deletions
+20 -18
View File
@@ -97,18 +97,18 @@ async def create_user(
if req.user_type == "frontend":
if not req.phone:
raise HTTPException(status_code=400, detail="前台用户必须填写手机号")
existing_phone = await db.execute(select(User).where(User.phone == req.phone))
existing_phone = await db.execute(select(User).where(User.phone == req.phone).limit(1))
if existing_phone.scalar_one_or_none():
raise HTTPException(status_code=400, detail="该手机号已注册")
username = f"用户{req.phone[-4:]}"
existing_name = await db.execute(select(User).where(User.username == username))
existing_name = await db.execute(select(User).where(User.username == username).limit(1))
if existing_name.scalar_one_or_none():
username = f"用户{req.phone[-4:]}{random.randint(10, 99)}"
else:
if not req.username:
raise HTTPException(status_code=400, detail="后台用户必须填写用户名")
username = req.username
existing = await db.execute(select(User).where(User.username == username))
existing = await db.execute(select(User).where(User.username == username).limit(1))
if existing.scalar_one_or_none():
raise HTTPException(status_code=400, detail="用户名已存在")
@@ -137,7 +137,7 @@ async def update_user_menus(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(User).where(User.id == user_id))
result = await db.execute(select(User).where(User.id == user_id).limit(1))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
@@ -153,7 +153,7 @@ async def get_user(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(User).where(User.id == user_id))
result = await db.execute(select(User).where(User.id == user_id).limit(1))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
@@ -204,7 +204,7 @@ async def reset_user_password(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(User).where(User.id == user_id))
result = await db.execute(select(User).where(User.id == user_id).limit(1))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
@@ -356,7 +356,7 @@ async def delete_admin_notification(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(Notification).where(Notification.id == notification_id)
select(Notification).where(Notification.id == notification_id).limit(1)
)
notif = result.scalar_one_or_none()
if not notif:
@@ -418,6 +418,7 @@ async def update_payment_config(
SystemConfig.id == config_id,
SystemConfig.key.like("payment_%"),
)
.limit(1)
)
config = result.scalar_one_or_none()
if not config:
@@ -497,7 +498,7 @@ async def update_industry_config(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(IndustryConfig).where(IndustryConfig.id == config_id)
select(IndustryConfig).where(IndustryConfig.id == config_id).limit(1)
)
config = result.scalar_one_or_none()
if not config:
@@ -520,7 +521,7 @@ async def delete_industry_config(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(IndustryConfig).where(IndustryConfig.id == config_id)
select(IndustryConfig).where(IndustryConfig.id == config_id).limit(1)
)
config = result.scalar_one_or_none()
if not config:
@@ -563,7 +564,7 @@ async def update_video_engine(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(VideoEngine).where(VideoEngine.id == engine_id)
select(VideoEngine).where(VideoEngine.id == engine_id).limit(1)
)
engine = result.scalar_one_or_none()
if not engine:
@@ -581,7 +582,7 @@ async def delete_video_engine(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(VideoEngine).where(VideoEngine.id == engine_id)
select(VideoEngine).where(VideoEngine.id == engine_id).limit(1)
)
engine = result.scalar_one_or_none()
if not engine:
@@ -624,7 +625,7 @@ async def update_image_engine(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(ImageEngine).where(ImageEngine.id == engine_id)
select(ImageEngine).where(ImageEngine.id == engine_id).limit(1)
)
engine = result.scalar_one_or_none()
if not engine:
@@ -642,7 +643,7 @@ async def delete_image_engine(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(ImageEngine).where(ImageEngine.id == engine_id)
select(ImageEngine).where(ImageEngine.id == engine_id).limit(1)
)
engine = result.scalar_one_or_none()
if not engine:
@@ -711,7 +712,7 @@ async def update_credit_ratio(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(CreditRatio).where(CreditRatio.id == ratio_id)
select(CreditRatio).where(CreditRatio.id == ratio_id).limit(1)
)
ratio = result.scalar_one_or_none()
if not ratio:
@@ -733,7 +734,7 @@ async def delete_credit_ratio(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(CreditRatio).where(CreditRatio.id == ratio_id)
select(CreditRatio).where(CreditRatio.id == ratio_id).limit(1)
)
ratio = result.scalar_one_or_none()
if not ratio:
@@ -790,7 +791,7 @@ async def update_model_config(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id))
result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id).limit(1))
config = result.scalar_one_or_none()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
@@ -806,7 +807,7 @@ async def delete_model_config(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id))
result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id).limit(1))
config = result.scalar_one_or_none()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
@@ -833,7 +834,7 @@ async def update_system_config(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(SystemConfig).where(SystemConfig.id == config_id))
result = await db.execute(select(SystemConfig).where(SystemConfig.id == config_id).limit(1))
config = result.scalar_one_or_none()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
@@ -1053,6 +1054,7 @@ async def admin_update_generation_status(
GenerationRecord.id == record_id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
record = result.scalar_one_or_none()
if not record:
+2 -2
View File
@@ -78,7 +78,7 @@ async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)):
)
# Check if phone already registered
existing = await db.execute(select(User).where(User.phone == req.phone))
existing = await db.execute(select(User).where(User.phone == req.phone).limit(1))
if existing.scalar_one_or_none():
from fastapi import HTTPException, status
raise HTTPException(
@@ -89,7 +89,7 @@ async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)):
# Create user with default username: 用户 + last 4 digits of phone
import random
username = f"用户{req.phone[-4:]}"
existing_name = await db.execute(select(User).where(User.username == username))
existing_name = await db.execute(select(User).where(User.username == username).limit(1))
if existing_name.scalar_one_or_none():
username = f"用户{req.phone[-4:]}{random.randint(10, 99)}"
+4
View File
@@ -228,6 +228,7 @@ async def optimize(
Project.user_id == current_user.id,
Project.deleted_at.is_(None),
)
.limit(1)
)
project = proj_result.scalar_one_or_none()
if not project:
@@ -460,6 +461,7 @@ async def update_prompt(
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
record = result.scalar_one_or_none()
if not record:
@@ -505,6 +507,7 @@ async def get_queue_status(
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
record = result.scalar_one_or_none()
if not record:
@@ -548,6 +551,7 @@ async def seedance_callback(request: Request, db: AsyncSession = Depends(get_db)
GenerationRecord.seedance_task_id == task_id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
record = result.scalar_one_or_none()
if not record:
@@ -416,6 +416,7 @@ async def get_task(
ChatGenerationTask.generation_mode == "chatapi_async",
ChatGenerationTask.deleted_at.is_(None),
)
.limit(1)
)
task = result.scalar_one_or_none()
if not task:
@@ -464,6 +465,7 @@ async def delete_task(
ChatGenerationTask.generation_mode == "chatapi_async",
ChatGenerationTask.deleted_at.is_(None),
)
.limit(1)
)
task = result.scalar_one_or_none()
if not task:
@@ -536,6 +538,7 @@ async def retry_task(
ChatGenerationTask.generation_mode == "chatapi_async",
ChatGenerationTask.deleted_at.is_(None),
)
.limit(1)
)
task = result.scalar_one_or_none()
if not task:
+2 -2
View File
@@ -65,7 +65,7 @@ async def update_menu_config(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id))
result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id).limit(1))
menu = result.scalar_one_or_none()
if not menu:
from fastapi import HTTPException, status
@@ -82,7 +82,7 @@ async def delete_menu_config(
admin: User = Depends(get_admin_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id))
result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id).limit(1))
menu = result.scalar_one_or_none()
if not menu:
from fastapi import HTTPException, status
+3 -2
View File
@@ -23,6 +23,7 @@ async def recharge(
RechargePackage.id == req.plan,
RechargePackage.is_active == True,
)
.limit(1)
)
pkg = result.scalar_one_or_none()
if not pkg:
@@ -45,7 +46,7 @@ async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)):
raise HTTPException(status_code=400, detail="签名验证失败")
order_no = data.get("out_trade_no")
result = await db.execute(
select(PaymentOrder).where(PaymentOrder.order_no == order_no)
select(PaymentOrder).where(PaymentOrder.order_no == order_no).limit(1)
)
order = result.scalar_one_or_none()
if order:
@@ -60,7 +61,7 @@ async def alipay_callback(request: Request, db: AsyncSession = Depends(get_db)):
raise HTTPException(status_code=400, detail="签名验证失败")
order_no = data.get("out_trade_no")
result = await db.execute(
select(PaymentOrder).where(PaymentOrder.order_no == order_no)
select(PaymentOrder).where(PaymentOrder.order_no == order_no).limit(1)
)
order = result.scalar_one_or_none()
if order:
+1
View File
@@ -60,6 +60,7 @@ async def delete_project(
Project.user_id == current_user.id,
Project.deleted_at.is_(None),
)
.limit(1)
)
project = result.scalar_one_or_none()
if not project:
@@ -77,7 +77,7 @@ async def update_package(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(RechargePackage).where(RechargePackage.id == pkg_id)
select(RechargePackage).where(RechargePackage.id == pkg_id).limit(1)
)
pkg = result.scalar_one_or_none()
if not pkg:
@@ -95,7 +95,7 @@ async def delete_package(
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(RechargePackage).where(RechargePackage.id == pkg_id)
select(RechargePackage).where(RechargePackage.id == pkg_id).limit(1)
)
pkg = result.scalar_one_or_none()
if not pkg:
+1 -1
View File
@@ -46,7 +46,7 @@ async def get_current_user(
detail="无效的凭证",
)
result = await db.execute(select(User).where(User.id == user_id))
result = await db.execute(select(User).where(User.id == user_id).limit(1))
user = result.scalar_one_or_none()
if not user or not user.is_active:
raise HTTPException(
+8 -6
View File
@@ -77,7 +77,7 @@ async def _seed_data():
db.add(admin_user)
# Seed demo user
result = await db.execute(select(User).where(User.username == "demo"))
result = await db.execute(select(User).where(User.username == "demo").limit(1))
demo = result.scalar_one_or_none()
if not demo:
demo_user = User(
@@ -114,7 +114,7 @@ async def _seed_data():
]
for key, value, desc in configs:
existing = await db.execute(
select(SystemConfig).where(SystemConfig.key == key)
select(SystemConfig).where(SystemConfig.key == key).limit(1)
)
if not existing.scalar_one_or_none():
db.add(
@@ -290,7 +290,7 @@ async def _seed_data():
]
for path, label, icon, order, target in default_menus:
existing = await db.execute(
select(MenuConfig).where(MenuConfig.path == path)
select(MenuConfig).where(MenuConfig.path == path).limit(1)
)
if not existing.scalar_one_or_none():
db.add(
@@ -320,6 +320,7 @@ async def _seed_data():
MenuConfig.menu_type == "group",
MenuConfig.menu_target == "admin",
)
.limit(1)
)
group = existing.scalar_one_or_none()
if not group:
@@ -364,6 +365,7 @@ async def _seed_data():
MenuConfig.path == path,
MenuConfig.menu_target == "admin",
)
.limit(1)
)
if not existing.scalar_one_or_none():
db.add(
@@ -391,7 +393,7 @@ async def _seed_data():
]
for name, credits, price, bonus, desc, ptype, order in default_packages:
existing = await db.execute(
select(RechargePackage).where(RechargePackage.name == name)
select(RechargePackage).where(RechargePackage.name == name).limit(1)
)
if not existing.scalar_one_or_none():
db.add(
@@ -418,7 +420,7 @@ async def _seed_data():
]
for key, label, icon, desc, order in default_industries:
existing = await db.execute(
select(IndustryConfig).where(IndustryConfig.key == key)
select(IndustryConfig).where(IndustryConfig.key == key).limit(1)
)
if not existing.scalar_one_or_none():
db.add(
@@ -571,7 +573,7 @@ def create_app() -> FastAPI:
# Update system config
async with async_session() as db:
result = await db.execute(
select(SystemConfig).where(SystemConfig.key == config_key)
select(SystemConfig).where(SystemConfig.key == config_key).limit(1)
)
config = result.scalar_one_or_none()
if config:
+2 -2
View File
@@ -38,11 +38,11 @@ def decode_access_token(token: str) -> str | None:
async def authenticate_user(
db: AsyncSession, username: str, password: str
) -> User | None:
result = await db.execute(select(User).where(User.username == username))
result = await db.execute(select(User).where(User.username == username).limit(1))
user = result.scalar_one_or_none()
if not user:
# Try phone number lookup for frontend users
result = await db.execute(select(User).where(User.phone == username))
result = await db.execute(select(User).where(User.phone == username).limit(1))
user = result.scalar_one_or_none()
if not user or not verify_password(password, user.hashed_password):
return None
+5 -3
View File
@@ -16,7 +16,7 @@ from app.utils.exceptions import InsufficientCreditsError
async def calc_text_credits(db: AsyncSession, input_tokens: int, output_tokens: int) -> float:
"""Calculate text credits based on actual token usage and configurable rate."""
result = await db.execute(
select(SystemConfig).where(SystemConfig.key == "text_credits_per_1000_tokens")
select(SystemConfig).where(SystemConfig.key == "text_credits_per_1000_tokens").limit(1)
)
config = result.scalar_one_or_none()
rate = float(config.value) if config else 1.0
@@ -78,6 +78,7 @@ async def calc_video_credits(
select(VideoEngine.id)
.where(VideoEngine.is_active == True)
.order_by(VideoEngine.priority.desc())
.limit(1)
)
engine_id = video_engines_result.scalar_one_or_none()
ratio = await _get_credit_ratio(
@@ -122,6 +123,7 @@ async def calc_image_credits(
select(ImageEngine.id)
.where(ImageEngine.is_active == True)
.order_by(ImageEngine.priority.desc())
.limit(1)
)
engine_id = image_engines_result.scalar_one_or_none()
ratio = await _get_credit_ratio(
@@ -148,7 +150,7 @@ async def deduct_credits(
) -> User:
"""Atomically deduct credits from user. Raises InsufficientCreditsError."""
result = await db.execute(
select(User).where(User.id == user_id)
select(User).where(User.id == user_id).limit(1)
)
user = result.scalar_one_or_none()
if not user or user.credits < amount:
@@ -178,7 +180,7 @@ async def add_credits(
) -> User:
"""Add credits to user."""
result = await db.execute(
select(User).where(User.id == user_id)
select(User).where(User.id == user_id).limit(1)
)
user = result.scalar_one_or_none()
if not user:
@@ -78,7 +78,9 @@ async def _get_video_engine(db: AsyncSession, engine_id: str | None) -> VideoEng
if engine_id:
query = query.where(VideoEngine.id == engine_id)
else:
query = query.order_by(VideoEngine.priority.desc()).limit(1)
query = query.order_by(VideoEngine.priority.desc())
query = query.limit(1)
result = await db.execute(query)
engine = result.scalar_one_or_none()
if not engine:
@@ -145,7 +145,7 @@ async def deduct_credits_locked_once(
if amount <= 0:
return BillingItem(charge_key=charge_key, amount=0.0, charged=False, skipped_reason="amount_lte_zero")
result = await db.execute(select(User).where(User.id == user_id).with_for_update())
result = await db.execute(select(User).where(User.id == user_id).with_for_update().limit(1))
user = result.scalar_one_or_none()
if not user:
raise ValueError("User not found")
@@ -35,9 +35,9 @@ async def get_runtime_engine(db: AsyncSession, task: ChatGenerationTask) -> Any:
if not task.engine_id:
raise ValueError("缺少 engine_id")
if task.gen_type == "image":
result = await db.execute(select(ImageEngine).where(ImageEngine.id == task.engine_id))
result = await db.execute(select(ImageEngine).where(ImageEngine.id == task.engine_id).limit(1))
else:
result = await db.execute(select(VideoEngine).where(VideoEngine.id == task.engine_id))
result = await db.execute(select(VideoEngine).where(VideoEngine.id == task.engine_id).limit(1))
engine = result.scalar_one_or_none()
if not engine:
raise ValueError("引擎不存在或已删除")
+1 -1
View File
@@ -180,7 +180,7 @@ async def _call_openai_compatible(
if industry_key and db is not None:
from app.models.industry_config import IndustryConfig
result = await db.execute(
select(IndustryConfig).where(IndustryConfig.key == industry_key)
select(IndustryConfig).where(IndustryConfig.key == industry_key).limit(1)
)
ind = result.scalar_one_or_none()
if ind and ind.skills:
+2 -1
View File
@@ -132,7 +132,7 @@ async def get_notifications(
async def mark_read(db: AsyncSession, notification_id: str, user_id: str) -> None:
"""Mark a notification as read for a specific user."""
result = await db.execute(
select(Notification).where(Notification.id == notification_id)
select(Notification).where(Notification.id == notification_id).limit(1)
)
notif = result.scalar_one_or_none()
if not notif:
@@ -150,6 +150,7 @@ async def mark_read(db: AsyncSession, notification_id: str, user_id: str) -> Non
NotificationRead.notification_id == notification_id,
NotificationRead.user_id == user_id,
)
.limit(1)
)
if not existing.scalar_one_or_none():
db.add(NotificationRead(
+1 -1
View File
@@ -104,7 +104,7 @@ async def process_payment_success(db: AsyncSession, order_id: str):
from sqlalchemy import select
result = await db.execute(
select(PaymentOrder).where(PaymentOrder.id == order_id)
select(PaymentOrder).where(PaymentOrder.id == order_id).limit(1)
)
order = result.scalar_one_or_none()
if not order or order.status != "pending":
@@ -84,6 +84,7 @@ async def _get_or_create_month_stat(
UserResourceMonthStat.user_id == user_id,
UserResourceMonthStat.stat_month == stat_month,
)
.limit(1)
)
stat = result.scalar_one_or_none()
if stat:
@@ -104,7 +105,7 @@ async def _get_or_create_total_stat(
user_id: str,
) -> UserResourceTotalStat:
result = await db.execute(
select(UserResourceTotalStat).where(UserResourceTotalStat.user_id == user_id)
select(UserResourceTotalStat).where(UserResourceTotalStat.user_id == user_id).limit(1)
)
stat = result.scalar_one_or_none()
if stat:
@@ -76,6 +76,7 @@ class TaskQueue:
GenerationRecord.id == record_id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
record = result.scalar_one_or_none()
if not record or record.status != "generating":
+1
View File
@@ -29,5 +29,6 @@ async def get_video_stream_url(db: AsyncSession, record_id: str) -> str | None:
GenerationRecord.id == record_id,
GenerationRecord.deleted_at.is_(None),
)
.limit(1)
)
return result.scalar_one_or_none()
@@ -109,7 +109,7 @@ async def _run(task_id: str):
result = await db.execute(select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
))
).limit(1))
task = result.scalar_one_or_none()
if not task or task.generation_mode != "chatapi_async":
@@ -236,7 +236,7 @@ async def _run(task_id: str):
result = await db.execute(select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
))
).limit(1))
task = result.scalar_one_or_none()
if task:
@@ -61,7 +61,7 @@ async def _reload_task(db, task_id: str) -> ChatGenerationTask | None:
select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
)
).limit(1)
)
return result.scalar_one_or_none()
@@ -72,7 +72,7 @@ async def _run(task_id: str):
select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
)
).limit(1)
)
task = result.scalar_one_or_none()
if not task or task.generation_mode != "chatapi_async":
@@ -41,7 +41,7 @@ async def _reload_task(db, task_id: str) -> ChatGenerationTask | None:
select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
)
).limit(1)
)
return result.scalar_one_or_none()
@@ -51,7 +51,7 @@ async def _run(task_id: str):
result = await db.execute(select(ChatGenerationTask).where(
ChatGenerationTask.id == task_id,
ChatGenerationTask.deleted_at.is_(None),
))
).limit(1))
task = result.scalar_one_or_none()
if not task or task.generation_mode != "chatapi_async":
return