完成项目信息管理的迁移

This commit is contained in:
2025-04-11 14:30:48 +08:00
parent 9e14a3256f
commit 4439687870
41 changed files with 276 additions and 1224 deletions

View File

@ -9,18 +9,25 @@ import application.settings
from . import schemas, models, params
from apps.vadmin.auth.utils.validation.auth import Auth
from utils import os_utils as os, random_utils as ru
from utils.huawei_obs import ObsClient
from utils import status
from core.exception import CustomException
if application.settings.DEBUG:
from application.config.development import datasets_url, runs_url, detect_url, yolo_url, images_url
from application.config.development import datasets_url, runs_url, images_url
else:
from application.config.production import datasets_url, runs_url, detect_url, yolo_url, images_url
from application.config.production import datasets_url, runs_url, images_url
from typing import Any, List
from core.crud import DalBase
from fastapi import UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, case, and_
class ProjectInfoDal(DalBase):
"""
项目信息
"""
def __init__(self, db: AsyncSession):
super(ProjectInfoDal, self).__init__()
@ -106,15 +113,112 @@ class ProjectInfoDal(DalBase):
class ProjectImageDal(DalBase):
"""
项目图片
"""
def __init__(self, db: AsyncSession):
super(ProjectImageDal, self).__init__()
self.db = db
self.model = models.ProjectImage
self.schema = schemas.ProjectImageSimpleOut
self.schema = schemas.ProjectImageOut
async def img_page(self, param: params.ProjectImageParams):
"""
分页查询图片信息,然后关联一个图片的标签数量
"""
subquery = (
select(
models.ProjectImgLabel.image_id,
func.ifnull(func.count(models.ProjectImgLabel.id), 0).label('label_count')
)
.group_by(models.ProjectImgLabel.image_id)
.subquery()
)
# 2 主查询
query = (
select(
models.ProjectImage,
func.ifnull(subquery.c.label_count, 0).label('label_count')
)
.outerjoin(subquery, models.ProjectImage.id == subquery.c.image_id)
)
v_where = [models.ProjectImage.project_id == param.project_id, models.ProjectImage.img_type == param.img_type]
sql = await self.filter_core(
v_start_sql=query,
v_where=v_where,
v_return_sql=True,
v_order=param.v_order,
v_order_field=param.v_order_field
)
count = await self.get_count_sql(sql)
if param.limit != 0:
sql = sql.offset((param.page - 1) * param.limit).limit(param.limit)
queryset = await self.db.execute(sql)
result = queryset.all()
datas = []
for result in result:
data = schemas.ProjectImageOut.model_validate(result[0])
data.label_count = int(result[1])
datas.append(data.model_dump())
return datas, count
async def upload_imgs(self, files: List[UploadFile], pro: schemas.ProjectInfoOut, img_type: str) -> int:
"""
上传项目图片
"""
image_models = []
for file in files:
image = models.ProjectImage()
image.project_id = pro.id
image.file_name = file.filename
image.img_type = img_type
# 保存原图
path = os.save_images(images_url, pro.project_no, file=file)
image.image_url = path
# 上传图片到obs
object_key = pro.project_no + '/' + img_type + '/' + file.filename
success, key, url = ObsClient.put_file(object_key=object_key, file_path=path)
if success:
image.object_key = object_key
image.thumb_image_url = url
else:
raise CustomException("obs上传失败", code=status.HTTP_ERROR)
image_models.append(image)
await self.create_datas(datas=image_models)
return len(image_models)
async def check_img_name(self, file_name: str, project_id: int, img_type: str):
"""
校验相同的项目,相同的文件类型是否有同名的文件
"""
count = await self.get_count(v_where=[
models.ProjectImage.file_name == file_name,
models.ProjectImage.project_id == project_id,
models.ProjectImage.img_type == img_type
])
return count > 0
async def del_img(self, ids: List[int]):
"""
删除图片删除数据库数据删除本地的文件删除obs中的文件
"""
file_urls = []
object_keys = []
for img_id in ids:
image = self.get_data(data_id=img_id)
if image:
file_urls.append(image.image_url)
object_keys.append(image.object_key)
os.delete_file_if_exists(**file_urls)
ObsClient.del_objects(object_keys)
await self.delete_datas(ids)
class ProjectLabelDal(DalBase):
"""
项目标签
"""
def __init__(self, db: AsyncSession):
super(ProjectLabelDal, self).__init__()
@ -139,18 +243,37 @@ class ProjectLabelDal(DalBase):
class ProjectImgLabelDal(DalBase):
"""
图片标签信息
"""
def __init__(self, db: AsyncSession):
super(ProjectImgLabelDal, self).__init__()
self.db = db
self.model = models.ProjectImgLabel
self.schema = schemas.ProjectImgLabelSimpleOut
async def add_img_label(self, img_label_in: schemas.ProjectImgLeaferLabel):
# 先把历史数据都删掉,然后再保存
image_id = img_label_in.image_id
await self.delete_datas(image_id=image_id)
img_labels = [self.model(**i.model_dump()) for i in img_label_in.label_infos]
for img in img_labels:
img.image_id = image_id
await self.create_datas(img_labels)
class ProjectImgLeaferDal(DalBase):
"""
图片标注信息-leafer.js
"""
def __init__(self, db: AsyncSession):
super(ProjectImgLeaferDal, self).__init__()
self.db = db
self.model = models.ProjectImgLeafer
self.schema = schemas.ProjectImgLeaferSimpleOut
self.schema = schemas.ProjectImgLeaferOut
async def add_leafer(self, img_label_in: schemas.ProjectImgLeaferLabel):
# 先把历史数据都删掉,然后再保存
image_id = img_label_in.image_id
await self.delete_datas(image_id=image_id)
await self.create_data(data=self.model(**img_label_in.model_dump()))

View File

@ -43,6 +43,7 @@ class ProjectImage(BaseModel):
img_type: Mapped[str] = mapped_column(String(10))
file_name: Mapped[str] = mapped_column(String(64), nullable=False)
image_url: Mapped[str] = mapped_column(String(255), nullable=False)
object_key: Mapped[str] = mapped_column(String(255), nullable=False)
thumb_image_url: Mapped[str] = mapped_column(String(255), nullable=False)
project_id: Mapped[int] = mapped_column(Integer)

View File

@ -15,11 +15,9 @@ class ProjectImageParams(QueryParams):
self,
img_type: str | None = Query(None, title="图片类别"),
project_id: int | None = Query(None, title="项目id"),
file_name: str | None = Query(None, title="文件名称"),
params: Paging = Depends()
):
super().__init__(params)
self.img_type = img_type
self.project_id = project_id
self.file_name = file_name

View File

@ -1,5 +1,5 @@
from .project_info import ProjectInfoIn, ProjectInfoOut, ProjectInfoPagerOut
from .project_image import ProjectImage, ProjectImagePager, ProjectImageOut
from .project_image import ProjectImageOut, ProjectImage
from .project_label import ProjectLabel
from .project_img_label import ProjectImgLabelIn
from .project_img_leafer import ProjectImgLeaferLabel, ProjectImgLeaferOut

View File

@ -14,8 +14,8 @@ from typing import Optional
class ProjectImage(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
file_name: Optional[str] = Field(None, description="文件名称")
thumb_image_url: Optional[str] = Field(None, description="图片在obs上的链接")
create_time: DatetimeStr
model_config = ConfigDict(from_attributes=True)
@ -25,14 +25,8 @@ class ProjectImageOut(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
file_name: Optional[str] = Field(None, description="文件名称")
thumb_image_url: Optional[str] = Field(None, description="图片在obs上的链接")
create_time: DatetimeStr
label_count: Optional[int]
model_config = ConfigDict(from_attributes=True)
class ProjectImagePager(BaseModel):
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
pagerNum: Optional[int] = Field(None, description="当前页码")
pagerSize: Optional[int] = Field(None, description="每页数量")

View File

@ -5,12 +5,11 @@
# @File : project_img_leafer.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from . import ProjectImgLabelIn
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, List
from . import ProjectImgLabelIn
class ProjectImgLeaferLabel(BaseModel):
image_id: Optional[int] = Field(..., description="图片id")

View File

@ -4,12 +4,13 @@
# @Create Time : 2025/04/03 10:25
# @File : views.py
# @IDE : PyCharm
# @desc : 路由,视图文件
# @desc : 路由,项目信息管理,包括项目主体,项目图片,项目标签和图片的标注信息
from utils.response import SuccessResponse, ErrorResponse
from . import params, schemas, crud, models
from core.dependencies import IdList
from fastapi import APIRouter, Depends
from typing import List
from fastapi import APIRouter, Depends, UploadFile, File, Form
from apps.vadmin.auth.utils.current import FullAdminAuth
from apps.vadmin.auth.utils.validation.auth import Auth
@ -42,7 +43,7 @@ async def add_project(
@app.get("/info/{pro_id}", summary="查询项目信息")
async def project(
async def project_info(
pro_id: int,
auth: Auth = Depends(FullAdminAuth())
):
@ -98,10 +99,64 @@ async def delete_label(
label_ids: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
# 删除标签信息,然后删除图片标签关联表
await crud.ProjectLabelDal(auth.db).delete_datas(label_ids.ids)
for label_id in label_ids.ids:
await crud.ProjectImgLabelDal(auth.db).delete_datas(label_id=label_id)
return SuccessResponse(msg="删除成功")
@app.get("/img", summary="获取图片列表,分两种情况,一个带分页的,一个不带分页的")
async def project_pager(
param: params.ProjectImageParams = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
if param.limit:
# 分页查询,关联一个标签数量
datas, count = await crud.ProjectImageDal(auth.db).img_page(param)
return SuccessResponse(data=datas, count=count)
else:
# 直接查询
datas = await crud.ProjectImageDal(auth.db).get_datas(v_schema=schemas.ProjectImage, **param.dict())
return SuccessResponse(data=datas)
@app.post("/img", summary="上传图片")
async def up_img(
project_id: int = Form(...),
files: List[UploadFile] = File(...),
img_type: str = Form(...),
auth: Auth = Depends(FullAdminAuth())
):
pro = await crud.ProjectInfoDal(auth.db).get_data(data_id=project_id)
if pro is None:
return ErrorResponse(msg="项目查询失败,请稍后再试")
count = await crud.ProjectImageDal(auth.db).upload_imgs(files=files, pro=pro, img_type=img_type)
if count > 0:
return SuccessResponse(msg="上传成功")
@app.delete("/img", summary="删除照片")
async def del_img(
img_id: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectImageDal(auth.db).del_img(img_id.ids)
return SuccessResponse(msg="删除成功")
@app.post("/img_label", summary="保存图片的标注信息")
async def add_img_label(
img_label_in: schemas.ProjectImgLeaferLabel,
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectImgLabelDal(auth.db).add_img_label(img_label_in)
await crud.ProjectImgLeaferDal(auth.db).add_leafer(img_label_in)
return SuccessResponse(msg="保存成功")