From 9b109a727044120ac773093ce730bbd7689690f3 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Tue, 28 Oct 2025 11:43:42 +0400 Subject: [PATCH] fix: applied timezone to default values, removed value nesting --- models/attribute.py | 14 +------ pyproject.toml | 2 +- repositories/attribute.py | 83 ++++++++++++++++++++++++++------------- schemas/attribute.py | 13 +++--- services/attribute.py | 16 ++++++-- services/deal_group.py | 3 +- uv.lock | 11 ------ 7 files changed, 80 insertions(+), 62 deletions(-) diff --git a/models/attribute.py b/models/attribute.py index 2d069b4..d518698 100644 --- a/models/attribute.py +++ b/models/attribute.py @@ -98,19 +98,9 @@ class AttributeValue(BaseModel): ) attribute: Mapped[Attribute] = relationship( back_populates="values", - lazy="joined", + lazy="noload", ) - def set_value(self, value: Optional[dict | str | bool | int | float]): - if value is None: - return - self.value = {"value": value} - - def get_value(self) -> Optional[dict | str | bool | int | float]: - if self.value is None: - return None - return self.value["value"] - class AttributeLabel(BaseModel): __tablename__ = "attribute_labels" @@ -132,5 +122,5 @@ class AttributeLabel(BaseModel): ) attribute: Mapped[Attribute] = relationship( backref="attribute_labels", - lazy="joined", + lazy="noload", ) diff --git a/pyproject.toml b/pyproject.toml index 1856301..bda2c76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ dependencies = [ "reportlab>=4.4.4", "pathlib>=1.0.1", "starlette>=0.47.2", - "lexorank>=1.0.1", "python-multipart>=0.0.20", + "lexorank-py==0.1.1", ] [dependency-groups] diff --git a/repositories/attribute.py b/repositories/attribute.py index 82c84b3..44d436b 100644 --- a/repositories/attribute.py +++ b/repositories/attribute.py @@ -1,3 +1,5 @@ +from collections import defaultdict + from sqlalchemy import and_ from sqlalchemy.orm import joinedload @@ -9,7 +11,11 @@ from models import ( module_attribute, ) from repositories.mixins import * -from schemas.attribute import CreateAttributeSchema, UpdateAttributeSchema, UpdateDealModuleAttributeSchema +from schemas.attribute import ( + CreateAttributeSchema, + UpdateAttributeSchema, + UpdateDealModuleAttributeSchema, +) from utils.exceptions import ForbiddenException @@ -83,7 +89,18 @@ class AttributeRepository( self, deal_id: int, module_id: int ) -> list[tuple[Attribute, AttributeValue, AttributeLabel]]: stmt = ( - select(Attribute, AttributeValue, AttributeLabel) + select( + Attribute, + AttributeValue, + AttributeLabel, + ) + .join( + module_attribute, + and_( + module_attribute.c.attribute_id == Attribute.id, + module_attribute.c.module_id == module_id, + ), + ) .outerjoin( AttributeValue, and_( @@ -99,25 +116,21 @@ class AttributeRepository( AttributeLabel.module_id == module_id, ), ) - .join( - module_attribute, - and_( - module_attribute.c.attribute_id == Attribute.id, - module_attribute.c.module_id == module_id, - ), + .where( + Attribute.is_deleted.is_(False), ) ) result = await self.session.execute(stmt) return list(result.all()) - async def _get_deal_attribute_values( - self, deal_id: int, module_id: int + async def _get_deals_attribute_values( + self, deal_ids: list[int], module_id: int ) -> list[AttributeValue]: stmt = ( select(AttributeValue) .join(Attribute, AttributeValue.attribute_id == Attribute.id) .where( - AttributeValue.deal_id == deal_id, + AttributeValue.deal_id.in_(deal_ids), AttributeValue.module_id == module_id, Attribute.is_deleted.is_(False), ) @@ -125,28 +138,44 @@ class AttributeRepository( result = await self.session.execute(stmt) return list(result.scalars().all()) - async def update_or_create_deal_attribute_values( + async def update_or_create_deals_attribute_values( self, - deal_id: int, + main_deal_id: int, + group_deal_ids: list[int], module_id: int, attributes: list[UpdateDealModuleAttributeSchema], ): - old_deal_attribute_values: list[AttributeValue] = await self._get_deal_attribute_values(deal_id, module_id) - dict_old_attrs: dict[int, AttributeValue] = {obj.attribute_id: obj for obj in old_deal_attribute_values} + old_deal_attribute_values: list[ + AttributeValue + ] = await self._get_deals_attribute_values(group_deal_ids, module_id) + + dict_old_attrs: dict[int, dict[int, AttributeValue]] = defaultdict(dict) + + for deal_attribute in old_deal_attribute_values: + dict_old_attrs[deal_attribute.deal_id][deal_attribute.attribute_id] = ( + deal_attribute + ) for attribute in attributes: - if attribute.attribute_id in dict_old_attrs: - # update - attribute_value = dict_old_attrs[attribute.attribute_id] - attribute_value.value = attribute.value + if attribute.is_applicable_to_group: + deal_ids_to_apply = group_deal_ids else: - # create - attribute_value = AttributeValue( - attribute_id=attribute.attribute_id, - deal_id=deal_id, - module_id=module_id, - value=attribute.value, - ) - self.session.add(attribute_value) + deal_ids_to_apply = [main_deal_id] + + for deal_id in deal_ids_to_apply: + if attribute.attribute_id in dict_old_attrs[deal_id]: + attribute_value = dict_old_attrs[deal_id][attribute.attribute_id] + attribute_value.value = attribute.value + else: + if attribute.value is None: + continue + + attribute_value = AttributeValue( + attribute_id=attribute.attribute_id, + deal_id=deal_id, + module_id=module_id, + value=attribute.value, + ) + self.session.add(attribute_value) await self.session.commit() diff --git a/schemas/attribute.py b/schemas/attribute.py index 91bf705..c28cb34 100644 --- a/schemas/attribute.py +++ b/schemas/attribute.py @@ -16,7 +16,7 @@ class CreateAttributeSchema(BaseSchema): label: str is_applicable_to_group: bool is_nullable: bool - default_value: Optional[dict[str, Any]] + default_value: Optional[Any] description: str type_id: int @@ -31,7 +31,7 @@ class UpdateAttributeSchema(BaseSchema): label: Optional[str] = None is_applicable_to_group: Optional[bool] = None is_nullable: Optional[bool] = None - default_value: Optional[dict[str, Any]] = None + default_value: Optional[Any] = None description: Optional[str] = None type: Optional[AttributeTypeSchema] = None @@ -44,9 +44,9 @@ class DealModuleAttributeSchema(BaseSchema): attribute_id: int label: str original_label: str - value: Optional[dict[str, Any]] + value: Optional[Any] type: AttributeTypeSchema - default_value: dict[str, Any] + default_value: Any description: str is_applicable_to_group: bool is_nullable: bool @@ -54,7 +54,8 @@ class DealModuleAttributeSchema(BaseSchema): class UpdateDealModuleAttributeSchema(BaseSchema): attribute_id: int - value: Optional[dict[str, Any]] + is_applicable_to_group: bool + value: Optional[Any] = None # endregion @@ -79,6 +80,7 @@ class UpdateAttributeLabelRequest(BaseSchema): class UpdateDealModuleAttributesRequest(BaseSchema): attributes: list[UpdateDealModuleAttributeSchema] + # endregion # region Response @@ -115,4 +117,5 @@ class GetDealModuleAttributesResponse(BaseSchema): class UpdateDealModuleAttributesResponse(BaseResponse): pass + # endregion diff --git a/services/attribute.py b/services/attribute.py index 1883192..76b82fd 100644 --- a/services/attribute.py +++ b/services/attribute.py @@ -1,5 +1,5 @@ from models import Attribute, AttributeValue, AttributeLabel -from repositories import AttributeRepository +from repositories import AttributeRepository, DealRepository from schemas.attribute import * from services.mixins import * @@ -43,7 +43,7 @@ class AttributeService( attribute_id=attr.id, label=attr_label.label if attr_label else attr.label, original_label=attr.label, - value=attr_value.value if attr_value else attr.default_value, + value=attr_value.value if attr_value else None, type=AttributeTypeSchema.model_validate(attr.type), default_value=attr.default_value, description=attr.description, @@ -57,7 +57,15 @@ class AttributeService( async def update_deal_module_attributes( self, deal_id: int, module_id: int, request: UpdateDealModuleAttributesRequest ) -> UpdateDealModuleAttributesResponse: - await self.repository.update_or_create_deal_attribute_values( - deal_id, module_id, request.attributes + deal_repo = DealRepository(self.repository.session) + deal = await deal_repo.get_by_id(deal_id) + if deal.group_id: + deals = await deal_repo.get_by_group_id(deal.group_id) + else: + deals = [deal] + + group_deal_ids = [d.id for d in deals] + await self.repository.update_or_create_deals_attribute_values( + deal_id, group_deal_ids, module_id, request.attributes ) return UpdateDealModuleAttributesResponse(message="Успешно сохранено") diff --git a/services/deal_group.py b/services/deal_group.py index 569f255..570d37f 100644 --- a/services/deal_group.py +++ b/services/deal_group.py @@ -1,5 +1,4 @@ -from lexorank import lexorank - +import lexorank from models import DealGroup, Deal from repositories import DealGroupRepository, DealRepository, DealTagRepository from schemas.deal_group import * diff --git a/uv.lock b/uv.lock index 9e1edf8..8885a67 100644 --- a/uv.lock +++ b/uv.lock @@ -362,7 +362,6 @@ dependencies = [ { name = "fastapi-endpoints" }, { name = "fpdf" }, { name = "gunicorn" }, - { name = "lexorank" }, { name = "orjson" }, { name = "pathlib" }, { name = "pdfrw" }, @@ -393,7 +392,6 @@ requires-dist = [ { name = "fastapi-endpoints", git = "https://github.com/vladNed/fastapi-endpoints.git?rev=main" }, { name = "fpdf", specifier = ">=1.7.2" }, { name = "gunicorn", specifier = ">=23.0.0" }, - { name = "lexorank", specifier = ">=1.0.1" }, { name = "orjson", specifier = ">=3.11.1" }, { name = "pathlib", specifier = ">=1.0.1" }, { name = "pdfrw", specifier = ">=0.4" }, @@ -694,15 +692,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] -[[package]] -name = "lexorank" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/58/87b3ced0716ea1997315b6f690edbe52d38f8145c12e56c35e1b7cfe306e/lexorank-1.0.1.tar.gz", hash = "sha256:e84869f626ddf4295cc848fd639a76f87bb8a17b2f649aa1d6449a4c53530fd7", size = 1758, upload-time = "2022-05-25T22:07:16.683Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/d7/b7bde2527103aeb4ddfd02e13b689a2c2ead51971276b4633e24fbbbdc68/lexorank-1.0.1-py3-none-any.whl", hash = "sha256:3a734155866e7c52b2e0e11f92226d002e79b7442271bf969b513aa5278b65c5", size = 1804, upload-time = "2022-05-25T22:07:15.03Z" }, -] - [[package]] name = "mako" version = "1.3.10"