groceries/backend/schemas.py

196 lines
4.3 KiB
Python

from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime
# Brand schemas
class BrandBase(BaseModel):
name: str
class BrandCreate(BrandBase):
pass
class BrandUpdate(BaseModel):
name: Optional[str] = None
class Brand(BrandBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
# BrandInShop schemas
class BrandInShopBase(BaseModel):
shop_id: int
brand_id: int
class BrandInShopCreate(BrandInShopBase):
pass
class BrandInShopUpdate(BaseModel):
shop_id: Optional[int] = None
brand_id: Optional[int] = None
class BrandInShop(BrandInShopBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
shop: "Shop"
brand: "Brand"
class Config:
from_attributes = True
# Grocery Category schemas
class GroceryCategoryBase(BaseModel):
name: str
class GroceryCategoryCreate(GroceryCategoryBase):
pass
class GroceryCategoryUpdate(BaseModel):
name: Optional[str] = None
class GroceryCategory(GroceryCategoryBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
# Grocery schemas
class GroceryBase(BaseModel):
name: str
category_id: int
class GroceryCreate(GroceryBase):
pass
class GroceryUpdate(BaseModel):
name: Optional[str] = None
category_id: Optional[int] = None
class Grocery(GroceryBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
category: GroceryCategory
class Config:
from_attributes = True
# Base schemas
class ProductBase(BaseModel):
name: str
grocery_id: int
brand_id: Optional[int] = None
organic: bool = False
weight: Optional[float] = None
weight_unit: str = "g"
class ProductCreate(ProductBase):
pass
class ProductUpdate(BaseModel):
name: Optional[str] = None
grocery_id: Optional[int] = None
brand_id: Optional[int] = None
organic: Optional[bool] = None
weight: Optional[float] = None
weight_unit: Optional[str] = None
class Product(ProductBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
grocery: Grocery
brand: Optional[Brand] = None
class Config:
from_attributes = True
# Shop schemas
class ShopBase(BaseModel):
name: str
city: str
address: Optional[str] = None
class ShopCreate(ShopBase):
pass
class ShopUpdate(BaseModel):
name: Optional[str] = None
city: Optional[str] = None
address: Optional[str] = None
class Shop(ShopBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
# Shopping Event schemas
class ProductInEvent(BaseModel):
product_id: int
amount: float = Field(..., gt=0)
price: float = Field(..., ge=0) # Price at the time of this shopping event (allow free items)
class ProductWithEventData(BaseModel):
id: int
name: str
grocery: Grocery
brand: Optional[Brand] = None
organic: bool
weight: Optional[float] = None
weight_unit: str
amount: float # Amount purchased in this event
price: float # Price at the time of this event
class Config:
from_attributes = True
class ShoppingEventBase(BaseModel):
shop_id: int
date: Optional[datetime] = None
total_amount: Optional[float] = Field(None, ge=0)
notes: Optional[str] = None
class ShoppingEventCreate(ShoppingEventBase):
products: List[ProductInEvent] = []
class ShoppingEventUpdate(BaseModel):
shop_id: Optional[int] = None
date: Optional[datetime] = None
total_amount: Optional[float] = Field(None, ge=0)
notes: Optional[str] = None
products: Optional[List[ProductInEvent]] = None
class ShoppingEventResponse(ShoppingEventBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
shop: Shop
products: List[ProductWithEventData] = []
class Config:
from_attributes = True
# Statistics schemas
class CategoryStats(BaseModel):
category: str
total_spent: float
item_count: int
avg_price: float
class ShopStats(BaseModel):
shop_name: str
total_spent: float
visit_count: int
avg_per_visit: float
# Update forward references
BrandInShop.model_rebuild()