feat: attr options and selects editing
This commit is contained in:
@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
|||||||
class AttributeSelect(BaseModel, IdMixin, SoftDeleteMixin):
|
class AttributeSelect(BaseModel, IdMixin, SoftDeleteMixin):
|
||||||
__tablename__ = "attribute_selects"
|
__tablename__ = "attribute_selects"
|
||||||
|
|
||||||
label: Mapped[str] = mapped_column()
|
name: Mapped[str] = mapped_column()
|
||||||
is_built_in: Mapped[bool] = mapped_column(
|
is_built_in: Mapped[bool] = mapped_column(
|
||||||
default=False,
|
default=False,
|
||||||
comment="Если встроенный select, то запрещено редактировать пользователю",
|
comment="Если встроенный select, то запрещено редактировать пользователю",
|
||||||
@ -33,7 +33,7 @@ class AttributeSelect(BaseModel, IdMixin, SoftDeleteMixin):
|
|||||||
class AttributeOption(BaseModel, IdMixin, SoftDeleteMixin):
|
class AttributeOption(BaseModel, IdMixin, SoftDeleteMixin):
|
||||||
__tablename__ = "attribute_options"
|
__tablename__ = "attribute_options"
|
||||||
|
|
||||||
label: Mapped[str] = mapped_column()
|
name: Mapped[str] = mapped_column()
|
||||||
|
|
||||||
select_id: Mapped[int] = mapped_column(ForeignKey("attribute_selects.id"))
|
select_id: Mapped[int] = mapped_column(ForeignKey("attribute_selects.id"))
|
||||||
select: Mapped[AttributeSelect] = relationship(
|
select: Mapped[AttributeSelect] = relationship(
|
||||||
|
|||||||
@ -7,3 +7,4 @@ from .deal_tag import DealTagRepository as DealTagRepository
|
|||||||
from .module import ModuleRepository as ModuleRepository
|
from .module import ModuleRepository as ModuleRepository
|
||||||
from .project import ProjectRepository as ProjectRepository
|
from .project import ProjectRepository as ProjectRepository
|
||||||
from .status import StatusRepository as StatusRepository
|
from .status import StatusRepository as StatusRepository
|
||||||
|
from .attr_option import AttrOptionRepository as AttrOptionRepository
|
||||||
|
|||||||
21
repositories/attr_option.py
Normal file
21
repositories/attr_option.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from sqlalchemy import Select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from models import AttributeOption
|
||||||
|
from repositories.mixins import RepCrudMixin
|
||||||
|
from schemas.attr_option import CreateAttrOptionSchema, UpdateAttrOptionSchema
|
||||||
|
|
||||||
|
|
||||||
|
class AttrOptionRepository(
|
||||||
|
RepCrudMixin[AttributeOption, CreateAttrOptionSchema, UpdateAttrOptionSchema],
|
||||||
|
):
|
||||||
|
session: AsyncSession
|
||||||
|
entity_class = AttributeOption
|
||||||
|
entity_not_found_msg = "Опция не найдена"
|
||||||
|
|
||||||
|
def _process_get_all_stmt_with_args(self, stmt: Select, *args) -> Select:
|
||||||
|
select_id = args[0]
|
||||||
|
return stmt.where(
|
||||||
|
AttributeOption.select_id == select_id,
|
||||||
|
AttributeOption.is_deleted.is_(False),
|
||||||
|
).order_by(AttributeOption.id)
|
||||||
@ -1,19 +1,12 @@
|
|||||||
from sqlalchemy import select
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from models import AttributeSelect, AttributeOption
|
from models import AttributeSelect
|
||||||
from repositories.base import BaseRepository
|
from repositories.mixins import RepCrudMixin
|
||||||
from repositories.mixins import RepGetAllMixin
|
from schemas.attr_select import UpdateAttrSelectSchema, CreateAttrSelectSchema
|
||||||
|
|
||||||
|
|
||||||
class AttrSelectRepository(BaseRepository, RepGetAllMixin[AttributeSelect]):
|
class AttrSelectRepository(
|
||||||
|
RepCrudMixin[AttributeSelect, CreateAttrSelectSchema, UpdateAttrSelectSchema],
|
||||||
|
):
|
||||||
session: AsyncSession
|
session: AsyncSession
|
||||||
entity_class = AttributeSelect
|
entity_class = AttributeSelect
|
||||||
|
|
||||||
async def get_options(self, select_id: int) -> list[AttributeOption]:
|
|
||||||
stmt = select(AttributeOption).where(
|
|
||||||
AttributeOption.select_id == select_id,
|
|
||||||
AttributeOption.is_deleted.is_(False),
|
|
||||||
)
|
|
||||||
result = await self.session.execute(stmt)
|
|
||||||
return list(result.scalars().all())
|
|
||||||
|
|||||||
56
routers/crm/v1/attr_option.py
Normal file
56
routers/crm/v1/attr_option.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from fastapi import APIRouter, Path
|
||||||
|
|
||||||
|
from backend.dependecies import SessionDependency
|
||||||
|
from schemas.attr_option import *
|
||||||
|
from services import AttrOptionService
|
||||||
|
|
||||||
|
router = APIRouter(tags=["attr_option"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/{selectId}",
|
||||||
|
response_model=GetAllAttrSelectOptionsResponse,
|
||||||
|
operation_id="get_attr_options",
|
||||||
|
)
|
||||||
|
async def get_attr_options(
|
||||||
|
session: SessionDependency,
|
||||||
|
select_id: int = Path(alias="selectId"),
|
||||||
|
):
|
||||||
|
return await AttrOptionService(session).get_all(select_id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/",
|
||||||
|
response_model=CreateAttrOptionResponse,
|
||||||
|
operation_id="create_attr_option",
|
||||||
|
)
|
||||||
|
async def create_attr_select(
|
||||||
|
session: SessionDependency,
|
||||||
|
request: CreateAttrOptionRequest,
|
||||||
|
):
|
||||||
|
return await AttrOptionService(session).create(request)
|
||||||
|
|
||||||
|
|
||||||
|
@router.patch(
|
||||||
|
"/{pk}",
|
||||||
|
response_model=UpdateAttrOptionResponse,
|
||||||
|
operation_id="update_attr_option",
|
||||||
|
)
|
||||||
|
async def update_attr_option(
|
||||||
|
session: SessionDependency,
|
||||||
|
request: UpdateAttrOptionRequest,
|
||||||
|
pk: int = Path(),
|
||||||
|
):
|
||||||
|
return await AttrOptionService(session).update(pk, request)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete(
|
||||||
|
"/{pk}",
|
||||||
|
response_model=DeleteAttrOptionResponse,
|
||||||
|
operation_id="delete_attr_option",
|
||||||
|
)
|
||||||
|
async def delete_attr_option(
|
||||||
|
session: SessionDependency,
|
||||||
|
pk: int = Path(),
|
||||||
|
):
|
||||||
|
return await AttrOptionService(session).delete(pk)
|
||||||
@ -18,13 +18,38 @@ async def get_attr_selects(
|
|||||||
return await AttrSelectService(session).get_all()
|
return await AttrSelectService(session).get_all()
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.post(
|
||||||
"/{selectId}",
|
"/",
|
||||||
response_model=GetAllAttrSelectOptionsResponse,
|
response_model=CreateAttrSelectResponse,
|
||||||
operation_id="get_attr_select_options",
|
operation_id="create_attr_select",
|
||||||
)
|
)
|
||||||
async def get_attr_select_options(
|
async def create_attr_select(
|
||||||
session: SessionDependency,
|
session: SessionDependency,
|
||||||
select_id: int = Path(alias="selectId"),
|
request: CreateAttrSelectRequest,
|
||||||
):
|
):
|
||||||
return await AttrSelectService(session).get_options(select_id)
|
return await AttrSelectService(session).create(request)
|
||||||
|
|
||||||
|
|
||||||
|
@router.patch(
|
||||||
|
"/{pk}",
|
||||||
|
response_model=UpdateAttrSelectResponse,
|
||||||
|
operation_id="update_attr_select",
|
||||||
|
)
|
||||||
|
async def update_attr_select(
|
||||||
|
session: SessionDependency,
|
||||||
|
request: UpdateAttrSelectRequest,
|
||||||
|
pk: int = Path(),
|
||||||
|
):
|
||||||
|
return await AttrSelectService(session).update(pk, request)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete(
|
||||||
|
"/{pk}",
|
||||||
|
response_model=DeleteAttrSelectResponse,
|
||||||
|
operation_id="delete_attr_select",
|
||||||
|
)
|
||||||
|
async def delete_attr_select(
|
||||||
|
session: SessionDependency,
|
||||||
|
pk: int = Path(),
|
||||||
|
):
|
||||||
|
return await AttrSelectService(session).delete(pk)
|
||||||
|
|||||||
55
schemas/attr_option.py
Normal file
55
schemas/attr_option.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from schemas.base import BaseSchema, BaseResponse
|
||||||
|
|
||||||
|
|
||||||
|
# region Entity
|
||||||
|
|
||||||
|
|
||||||
|
class AttrOptionSchema(BaseSchema):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAttrOptionSchema(BaseSchema):
|
||||||
|
name: str
|
||||||
|
select_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAttrOptionSchema(BaseSchema):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Request
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAttrOptionRequest(BaseSchema):
|
||||||
|
entity: CreateAttrOptionSchema
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAttrOptionRequest(BaseSchema):
|
||||||
|
entity: UpdateAttrOptionSchema
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Response
|
||||||
|
|
||||||
|
|
||||||
|
class GetAllAttrSelectOptionsResponse(BaseSchema):
|
||||||
|
items: list[AttrOptionSchema]
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAttrOptionResponse(BaseSchema):
|
||||||
|
entity: AttrOptionSchema
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAttrOptionResponse(BaseResponse):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteAttrOptionResponse(BaseSchema):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
@ -1,4 +1,5 @@
|
|||||||
from schemas.base import BaseSchema
|
from schemas.attr_option import AttrOptionSchema
|
||||||
|
from schemas.base import BaseSchema, BaseResponse
|
||||||
|
|
||||||
|
|
||||||
# region Entity
|
# region Entity
|
||||||
@ -6,13 +7,16 @@ from schemas.base import BaseSchema
|
|||||||
|
|
||||||
class AttrSelectSchema(BaseSchema):
|
class AttrSelectSchema(BaseSchema):
|
||||||
id: int
|
id: int
|
||||||
label: str
|
name: str
|
||||||
is_built_in: bool
|
is_built_in: bool
|
||||||
|
|
||||||
|
|
||||||
class AttrOptionSchema(BaseSchema):
|
class CreateAttrSelectSchema(BaseSchema):
|
||||||
id: int
|
name: str
|
||||||
label: str
|
|
||||||
|
|
||||||
|
class UpdateAttrSelectSchema(BaseSchema):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
class AttrSelectWithOptionsSchema(AttrSelectSchema):
|
class AttrSelectWithOptionsSchema(AttrSelectSchema):
|
||||||
@ -24,6 +28,14 @@ class AttrSelectWithOptionsSchema(AttrSelectSchema):
|
|||||||
# region Request
|
# region Request
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAttrSelectRequest(BaseSchema):
|
||||||
|
entity: CreateAttrSelectSchema
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAttrSelectRequest(BaseSchema):
|
||||||
|
entity: UpdateAttrSelectSchema
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region Response
|
# region Response
|
||||||
@ -33,8 +45,16 @@ class GetAllAttrSelectsResponse(BaseSchema):
|
|||||||
items: list[AttrSelectSchema]
|
items: list[AttrSelectSchema]
|
||||||
|
|
||||||
|
|
||||||
class GetAllAttrSelectOptionsResponse(BaseSchema):
|
class CreateAttrSelectResponse(BaseResponse):
|
||||||
items: list[AttrOptionSchema]
|
entity: AttrSelectSchema
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateAttrSelectResponse(BaseResponse):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteAttrSelectResponse(BaseResponse):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|||||||
@ -6,3 +6,4 @@ from .deal_group import DealGroupService as DealGroupService
|
|||||||
from .deal_tag import DealTagService as DealTagService
|
from .deal_tag import DealTagService as DealTagService
|
||||||
from .project import ProjectService as ProjectService
|
from .project import ProjectService as ProjectService
|
||||||
from .status import StatusService as StatusService
|
from .status import StatusService as StatusService
|
||||||
|
from .attr_option import AttrOptionService as AttrOptionService
|
||||||
|
|||||||
27
services/attr_option.py
Normal file
27
services/attr_option.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from models import AttributeOption
|
||||||
|
from repositories import AttrOptionRepository
|
||||||
|
from schemas.attr_option import (
|
||||||
|
AttrOptionSchema,
|
||||||
|
CreateAttrOptionRequest,
|
||||||
|
UpdateAttrOptionRequest,
|
||||||
|
)
|
||||||
|
from services.mixins import ServiceCrudMixin
|
||||||
|
|
||||||
|
|
||||||
|
class AttrOptionService(
|
||||||
|
ServiceCrudMixin[
|
||||||
|
AttributeOption,
|
||||||
|
AttrOptionSchema,
|
||||||
|
CreateAttrOptionRequest,
|
||||||
|
UpdateAttrOptionRequest,
|
||||||
|
]
|
||||||
|
):
|
||||||
|
schema_class = AttrOptionSchema
|
||||||
|
entity_deleted_msg = "Опция успешно удалена"
|
||||||
|
entity_updated_msg = "Опция успешно обновлена"
|
||||||
|
entity_created_msg = "Опция успешно создана"
|
||||||
|
|
||||||
|
def __init__(self, session: AsyncSession):
|
||||||
|
self.repository = AttrOptionRepository(session)
|
||||||
@ -4,21 +4,21 @@ from models import AttributeSelect
|
|||||||
from repositories import AttrSelectRepository
|
from repositories import AttrSelectRepository
|
||||||
from schemas.attr_select import (
|
from schemas.attr_select import (
|
||||||
AttrSelectSchema,
|
AttrSelectSchema,
|
||||||
GetAllAttrSelectOptionsResponse,
|
CreateAttrSelectRequest,
|
||||||
AttrOptionSchema,
|
UpdateAttrSelectRequest,
|
||||||
)
|
)
|
||||||
from services.mixins import ServiceGetAllMixin
|
from services.mixins import ServiceCrudMixin
|
||||||
|
|
||||||
|
|
||||||
class AttrSelectService(ServiceGetAllMixin[AttributeSelect, AttrSelectSchema]):
|
class AttrSelectService(
|
||||||
|
ServiceCrudMixin[
|
||||||
|
AttributeSelect,
|
||||||
|
AttrSelectSchema,
|
||||||
|
CreateAttrSelectRequest,
|
||||||
|
UpdateAttrSelectRequest,
|
||||||
|
]
|
||||||
|
):
|
||||||
schema_class = AttrSelectSchema
|
schema_class = AttrSelectSchema
|
||||||
|
|
||||||
def __init__(self, session: AsyncSession):
|
def __init__(self, session: AsyncSession):
|
||||||
self.repository = AttrSelectRepository(session)
|
self.repository = AttrSelectRepository(session)
|
||||||
|
|
||||||
async def get_options(self, select_id: int) -> GetAllAttrSelectOptionsResponse:
|
|
||||||
options = await self.repository.get_options(select_id)
|
|
||||||
|
|
||||||
return GetAllAttrSelectOptionsResponse(
|
|
||||||
items=[AttrOptionSchema.model_validate(option) for option in options]
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user