import ali

This commit is contained in:
2026-02-01 01:45:51 +01:00
parent bdbfa4e25a
commit 46d6d88ce5
48 changed files with 6714 additions and 185 deletions
+61 -1
View File
@@ -5,8 +5,9 @@ Définit les schémas de validation pour les requêtes et réponses API.
from datetime import date, datetime
from decimal import Decimal
from typing import Any
from pydantic import BaseModel, ConfigDict, Field
from pydantic import BaseModel, ConfigDict, Field, model_validator
from app.models.item import ItemStatus
from app.schemas.category import CategoryResponse
@@ -26,6 +27,7 @@ class ItemBase(BaseModel):
url: str | None = Field(None, max_length=500, description="Lien vers page produit")
price: Decimal | None = Field(None, ge=0, decimal_places=2, description="Prix d'achat")
purchase_date: date | None = Field(None, description="Date d'achat")
characteristics: dict[str, str] | None = Field(None, description="Caractéristiques techniques (clé-valeur)")
notes: str | None = Field(None, description="Notes libres")
@@ -34,6 +36,8 @@ class ItemCreate(ItemBase):
category_id: int = Field(..., description="ID de la catégorie")
location_id: int = Field(..., description="ID de l'emplacement")
parent_item_id: int | None = Field(None, description="ID de l'objet parent (si intégré)")
shop_id: int | None = Field(None, description="ID de la boutique d'achat")
class ItemUpdate(BaseModel):
@@ -49,9 +53,12 @@ class ItemUpdate(BaseModel):
url: str | None = Field(None, max_length=500)
price: Decimal | None = Field(None, ge=0)
purchase_date: date | None = None
characteristics: dict[str, str] | None = None
notes: str | None = None
category_id: int | None = None
location_id: int | None = None
parent_item_id: int | None = None
shop_id: int | None = None
class ItemResponse(ItemBase):
@@ -62,6 +69,8 @@ class ItemResponse(ItemBase):
id: int
category_id: int
location_id: int
parent_item_id: int | None = None
shop_id: int | None = None
created_at: datetime
updated_at: datetime
@@ -71,6 +80,57 @@ class ItemWithRelations(ItemResponse):
category: CategoryResponse
location: LocationResponse
thumbnail_id: int | None = None
parent_item_name: str | None = None
@model_validator(mode="before")
@classmethod
def extract_computed_fields(cls, data: Any) -> Any:
"""Extrait les champs calculés : thumbnail et nom du parent."""
from sqlalchemy.orm import InstanceState
thumbnail_id = None
parent_item_name = None
# Vérifier que les relations sont chargées (éviter lazy load en async)
loaded_relations: set[str] = set()
if hasattr(data, "_sa_instance_state"):
state: InstanceState = data._sa_instance_state
loaded_relations = set(state.dict.keys())
if "documents" in loaded_relations:
for doc in data.documents:
if doc.type.value == "photo":
thumbnail_id = doc.id
break
if "parent_item" in loaded_relations and data.parent_item is not None:
parent_item_name = data.parent_item.name
if isinstance(data, dict):
if thumbnail_id:
data["thumbnail_id"] = thumbnail_id
if parent_item_name:
data["parent_item_name"] = parent_item_name
elif thumbnail_id or parent_item_name:
result = {}
for k in dir(data):
if k.startswith("_"):
continue
# Ne pas accéder aux relations non chargées
if k in ("documents", "parent_item", "children", "shop"):
continue
try:
result[k] = getattr(data, k)
except Exception:
pass
if thumbnail_id:
result["thumbnail_id"] = thumbnail_id
if parent_item_name:
result["parent_item_name"] = parent_item_name
return result
return data
class ItemSummary(BaseModel):