Files
shop-pip/app/main.py
T

98 lines
2.5 KiB
Python

import time
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import Depends, FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from sqlalchemy import select
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import Session
from app.config import get_settings
from app.database import Base, engine, get_db
from app.models import Category, Product
from app.seed import seed_if_empty
BASE_DIR = Path(__file__).resolve().parent
settings = get_settings()
def wait_for_db(retries: int = 30, delay: float = 1.0) -> None:
for attempt in range(1, retries + 1):
try:
with engine.connect() as conn:
conn.exec_driver_sql("SELECT 1")
return
except OperationalError:
if attempt == retries:
raise
time.sleep(delay)
@asynccontextmanager
async def lifespan(_: FastAPI):
wait_for_db()
Base.metadata.create_all(bind=engine)
from app.database import SessionLocal
db = SessionLocal()
try:
seed_if_empty(db)
finally:
db.close()
yield
app = FastAPI(title=settings.app_name, lifespan=lifespan)
app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static")
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
def format_price(value) -> str:
try:
amount = float(value)
except (TypeError, ValueError):
return str(value)
formatted = f"{amount:,.0f}".replace(",", " ")
return f"{formatted} ₽"
templates.env.filters["rub"] = format_price
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}
@app.get("/", response_class=HTMLResponse)
def home(request: Request, db: Session = Depends(get_db)):
categories = db.scalars(
select(Category).order_by(Category.sort_order, Category.name)
).all()
featured = db.scalars(
select(Product)
.where(Product.is_active.is_(True), Product.is_featured.is_(True))
.order_by(Product.id)
.limit(4)
).all()
products = db.scalars(
select(Product)
.where(Product.is_active.is_(True))
.order_by(Product.is_featured.desc(), Product.id)
.limit(12)
).all()
return templates.TemplateResponse(
request,
"index.html",
{
"app_name": settings.app_name,
"categories": categories,
"featured": featured,
"products": products,
},
)