重构表结构:合并 profiles→users,展平 API 响应,新增计数器字段
- models: 删除 Profile 模型,字段合并到 User;User 新增云朵/公开/收藏计数器;Cloud 新增 favorite_count - schemas/serializers: 展平 UserOut/AuthOut/MeOut/AdminUserOut,移除嵌套 profile - deps: user.profile.role→user.role,移除 selectinload profile - auth/register: 注册时直接设置 user 字段,不再创建 Profile - clouds: 创建/删除云朵时同步 user.cloud_count 计数器,状态变化时同步 public_cloud_count - favorites: 点赞/取消时同步 cloud.favorite_count 计数器 - admin: 审批/隐藏/批量删时同步 public_cloud_count 计数器 - profiles/stats: 用计数器替代实时 COUNT 查询 - alembic: 新增 migration 合并 profiles 到 users,初始化 counters
This commit is contained in:
+26
-22
@@ -2,7 +2,7 @@ import math
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query, status
|
||||
from sqlalchemy import delete, func, select
|
||||
from sqlalchemy import case, delete, func, select, update
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
|
||||
from sqlalchemy.orm import joinedload
|
||||
@@ -18,7 +18,7 @@ router = APIRouter(tags=["点赞收藏"])
|
||||
|
||||
def _cloud_options():
|
||||
return (
|
||||
joinedload(Cloud.user).joinedload(User.profile),
|
||||
joinedload(Cloud.user),
|
||||
joinedload(Cloud.cloud_type),
|
||||
)
|
||||
|
||||
@@ -35,23 +35,12 @@ async def _get_visible_cloud(
|
||||
if not cloud:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="图片不存在")
|
||||
|
||||
can_manage = cloud.user_id == user.id or user.profile.role == "admin"
|
||||
can_manage = cloud.user_id == user.id or user.role == "admin"
|
||||
if not can_manage and (cloud.status != "approved" or cloud.is_hidden):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="图片不存在")
|
||||
return cloud
|
||||
|
||||
|
||||
async def _favorite_count(db: DbSession, cloud_id: uuid.UUID) -> int:
|
||||
return (
|
||||
await db.scalar(
|
||||
select(func.count())
|
||||
.select_from(CloudFavorite)
|
||||
.where(CloudFavorite.cloud_id == cloud_id)
|
||||
)
|
||||
or 0
|
||||
)
|
||||
|
||||
|
||||
async def _is_favorited(db: DbSession, user_id: uuid.UUID, cloud_id: uuid.UUID) -> bool:
|
||||
favorite_id = await db.scalar(
|
||||
select(CloudFavorite.id).where(
|
||||
@@ -71,11 +60,12 @@ async def _favorite_out(
|
||||
) -> FavoriteOut:
|
||||
if favorited is None:
|
||||
favorited = await _is_favorited(db, user_id, cloud_id)
|
||||
cloud = await db.get(Cloud, cloud_id)
|
||||
return FavoriteOut(
|
||||
cloud_id=cloud_id,
|
||||
user_id=user_id,
|
||||
favorited=favorited,
|
||||
favorite_count=await _favorite_count(db, cloud_id),
|
||||
favorite_count=cloud.favorite_count if cloud else 0,
|
||||
)
|
||||
|
||||
|
||||
@@ -89,11 +79,10 @@ async def get_cloud_favorite(
|
||||
description="要查询的用户 ID;默认当前登录用户。仅本人或管理员可查他人。",
|
||||
),
|
||||
) -> FavoriteOut:
|
||||
"""查询某用户对某张照片的点赞/收藏状态。"""
|
||||
await _get_visible_cloud(db, cloud_id, user)
|
||||
|
||||
target_user_id = user_id or user.id
|
||||
if target_user_id != user.id and user.profile.role != "admin":
|
||||
if target_user_id != user.id and user.role != "admin":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="只能查询自己的喜欢状态",
|
||||
@@ -109,27 +98,43 @@ async def set_cloud_favorite(
|
||||
user: CurrentUser,
|
||||
db: DbSession,
|
||||
) -> FavoriteOut:
|
||||
"""点赞/收藏照片,或取消。"""
|
||||
await _get_visible_cloud(db, cloud_id, user)
|
||||
|
||||
if payload.favorited:
|
||||
insert_factory = (
|
||||
pg_insert if db.bind and db.bind.dialect.name == "postgresql" else sqlite_insert
|
||||
)
|
||||
await db.execute(
|
||||
result = await db.execute(
|
||||
insert_factory(CloudFavorite)
|
||||
.values(user_id=user.id, cloud_id=cloud_id)
|
||||
.on_conflict_do_nothing(
|
||||
index_elements=[CloudFavorite.user_id, CloudFavorite.cloud_id]
|
||||
)
|
||||
)
|
||||
if result.rowcount and result.rowcount > 0:
|
||||
await db.execute(
|
||||
update(Cloud)
|
||||
.where(Cloud.id == cloud_id)
|
||||
.values(favorite_count=Cloud.favorite_count + 1)
|
||||
)
|
||||
else:
|
||||
await db.execute(
|
||||
result = await db.execute(
|
||||
delete(CloudFavorite).where(
|
||||
CloudFavorite.user_id == user.id,
|
||||
CloudFavorite.cloud_id == cloud_id,
|
||||
)
|
||||
)
|
||||
if result.rowcount and result.rowcount > 0:
|
||||
await db.execute(
|
||||
update(Cloud)
|
||||
.where(Cloud.id == cloud_id)
|
||||
.values(
|
||||
favorite_count=case(
|
||||
(Cloud.favorite_count > 0, Cloud.favorite_count - 1),
|
||||
else_=0,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
return await _favorite_out(
|
||||
@@ -147,7 +152,6 @@ async def list_my_favorites(
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(50, ge=1, le=100),
|
||||
) -> PageOut[CloudOut]:
|
||||
"""当前用户点赞收藏的照片列表(按收藏时间倒序)。"""
|
||||
total = (
|
||||
await db.scalar(
|
||||
select(func.count())
|
||||
@@ -166,7 +170,7 @@ async def list_my_favorites(
|
||||
.limit(page_size)
|
||||
)
|
||||
items = [
|
||||
cloud_out(item, include_private=item.user_id == user.id or user.profile.role == "admin")
|
||||
cloud_out(item, include_private=item.user_id == user.id or user.role == "admin")
|
||||
for item in result.scalars().unique().all()
|
||||
]
|
||||
return PageOut(
|
||||
|
||||
Reference in New Issue
Block a user