generated from gilles/template-webapp
import ali
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Schémas Pydantic pour les boutiques."""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class ShopBase(BaseModel):
|
||||
"""Schéma de base pour les boutiques."""
|
||||
|
||||
name: str = Field(..., min_length=1, max_length=200, description="Nom de la boutique")
|
||||
description: str | None = Field(None, max_length=1000, description="Description optionnelle")
|
||||
url: str | None = Field(None, max_length=500, description="URL du site web")
|
||||
address: str | None = Field(None, description="Adresse physique")
|
||||
|
||||
|
||||
class ShopCreate(ShopBase):
|
||||
"""Schéma pour la création d'une boutique."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ShopUpdate(BaseModel):
|
||||
"""Schéma pour la mise à jour d'une boutique (tous les champs optionnels)."""
|
||||
|
||||
name: str | None = Field(None, min_length=1, max_length=200)
|
||||
description: str | None = Field(None, max_length=1000)
|
||||
url: str | None = Field(None, max_length=500)
|
||||
address: str | None = None
|
||||
|
||||
|
||||
class ShopResponse(ShopBase):
|
||||
"""Schéma de réponse pour une boutique."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class ShopWithItemCount(ShopResponse):
|
||||
"""Schéma de réponse avec le nombre d'objets."""
|
||||
|
||||
item_count: int = Field(default=0, description="Nombre d'objets achetés dans cette boutique")
|
||||
Reference in New Issue
Block a user