from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey from sqlalchemy.dialects.mysql import DECIMAL from sqlalchemy.sql import func, select from sqlalchemy.orm import relationship from pydantic import BaseModel, Field from typing import Optional, List from datetime import datetime from .database import Base # 商家图片表 class MerchantImageDB(Base): __tablename__ = "merchant_images" id = Column(Integer, primary_key=True, autoincrement=True) merchant_id = Column(Integer, ForeignKey("merchants.id", ondelete="CASCADE"), index=True) image_url = Column(String(500), nullable=False) sort = Column(Integer, nullable=False, default=0) create_time = Column(DateTime(timezone=True), server_default=func.now()) class Config: unique_together = [("merchant_id", "sort")] # 数据库模型 class MerchantDB(Base): __tablename__ = "merchants" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(100), nullable=False) business_hours = Column(String(100), nullable=False) # 营业时间,如 "09:00-22:00" address = Column(String(200), nullable=False) longitude = Column(DECIMAL(9, 6), nullable=False) # 经度,精确到小数点后6位 latitude = Column(DECIMAL(9, 6), nullable=False) # 纬度,精确到小数点后6位 phone = Column(String(20), nullable=False) create_time = Column(DateTime(timezone=True), server_default=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now()) # 关联图片 images = relationship("MerchantImageDB", order_by="MerchantImageDB.sort", cascade="all, delete-orphan") # Pydantic 模型 class MerchantImage(BaseModel): image_url: str = Field(..., max_length=500) sort: int = Field(..., ge=0) # 排序序号,从0开始 class Config: from_attributes = True class MerchantCreate(BaseModel): name: str = Field(..., max_length=100) business_hours: str = Field(..., max_length=100) address: str = Field(..., max_length=200) longitude: float = Field(..., ge=-180, le=180, description="经度") latitude: float = Field(..., ge=-90, le=90, description="纬度") phone: str = Field(..., max_length=20, pattern=r'^\d+$') images: List[MerchantImage] = [] class MerchantUpdate(BaseModel): name: Optional[str] = Field(None, max_length=100) business_hours: Optional[str] = Field(None, max_length=100) address: Optional[str] = Field(None, max_length=200) longitude: Optional[float] = Field(None, ge=-180, le=180, description="经度") latitude: Optional[float] = Field(None, ge=-90, le=90, description="纬度") phone: Optional[str] = Field(None, max_length=20, pattern=r'^\d+$') images: Optional[List[MerchantImage]] = None class MerchantInfo(BaseModel): id: int name: str business_hours: str address: str longitude: float latitude: float phone: str images: List[MerchantImage] create_time: datetime update_time: Optional[datetime] distance: Optional[int] = None # 距离(米) class Config: from_attributes = True