完成项目信息管理的迁移
This commit is contained in:
@ -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()))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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="每页数量")
|
||||
|
@ -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")
|
||||
|
@ -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="保存成功")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user