如何在SQLModel中为Company模型定义嵌套Address字段且不新增数据表
解决方案
1. 定义Address Schema(无需生成数据库表)
让Address继承SQLModel但不设置table=True,这样它仅作为数据结构的验证和序列化Schema,不会在数据库中创建独立表:
from sqlmodel import SQLModel class Address(SQLModel): street_address: str city: str state: str country: str postal_code: int
2. 修改Company数据库模型
在Company模型中直接使用Address作为字段类型,同时通过Field指定数据库存储为JSON格式,SQLModel会自动处理对象与JSON的序列化/反序列化:
from typing import Optional from sqlmodel import SQLModel, Field, JSON from sqlalchemy import Column class Company(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) # 建议添加主键字段 name: str = Field(index=True, unique=True) email: str phone: int postal_address: Address = Field(default_factory=Address, sa_column=Column(JSON)) shipping_address: Optional[Address] = Field(default=None, sa_column=Column(JSON))
这里default_factory=Address用于生成默认的空Address实例(若不需要默认值可调整),无需手动编写validator,Address Schema本身会自动校验所有必填字段。
3. 修复FastAPI 422错误的请求模型处理
复用已定义的Address Schema来构建请求模型,避免重复代码,同时确保请求数据格式与数据库模型匹配:
from datetime import date from sqlmodel import SQLModel # 直接继承Address,无需重复定义字段 class AddressRequest(Address): pass class CompanyRequest(SQLModel): name: str email: str phone: int postal_address: AddressRequest shipping_address: Optional[AddressRequest] gst_no: str fy_start: date fy_end: date
在FastAPI接口中,通过model_validate方法将请求模型转换为数据库模型:
from fastapi import FastAPI from sqlmodel import Session, create_engine app = FastAPI() engine = create_engine("sqlite:///./test.db") @app.post("/companies/") def create_company(company_data: CompanyRequest): db_company = Company.model_validate(company_data) with Session(engine) as session: session.add(db_company) session.commit() session.refresh(db_company) return db_company
核心优势
- 无需手动编写字典字段的校验逻辑,Address Schema自动完成必填字段验证
- 数据库中仅存储JSON格式的地址数据,无需创建独立地址表或关联关系
- 请求模型与数据库模型复用同一Schema,避免格式不一致导致的422错误
内容的提问来源于stack exchange,提问作者Sourabh Patel
相关产品推荐
相关产品推荐

