21.FastAPI关系型数据处理
在FastAPI应用程序开发中,不可避免要使用关系型数据库,FastAPI本身并不要求使用关系型数据库。但在开发中可以根据自己的需求使用任何关系型数据库。这里,我们以PostgreSQL数据库及SQLAlchemy为例来说明在FastAPI应用程序开发中使用数据库的方法。
在本例中,实现一个通讯录的管理和维护,包括通讯录的增删改查操作。该例不使用ORM来实现,以原生SQL +SQLALchemy的方式来实现,SQLALchemy只用于执行SQL语句,不使用其ORM的方式。
21.1设计并创建数据表
create table test.d_address_book( address_book_id varchar(64) primary key, --id name varchar(32), --姓名 sex varchar(2), --性别 mobile varchar(16), --手机号码 email varchar(256), --电子邮箱 qq varchar(32), --QQ号 com_name varchar(128), --单位名称 post_address varchar(256), --通讯地址 remarks varchar(256) --备注 );
21.2创建pydantic模型
class AddressBook(BaseModel): address_book_id: Optional[str] = None name: str = Field(...) sex: str = Field(...) mobile: str = Field(...) email: str = Field(...) qq: str = Field(...) com_name: str = Field(...) post_address: str = Field(...) remarks: Optional[str] = None
上面的pydantic模型与数据库表test.d_address_book的字段名保持一致。
21.3建立数据库连接
在项目中新建一个database.py文件,用于连接数据库,代码如下:
# coding: utf-8 from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker # 数据库连接url SQLALCHEMY_DATABASE_URL = "postgresql://postgres:jane10181010@127.0.0.1:9432/qydb" # 创建数据库连接 engine = create_engine( SQLALCHEMY_DATABASE_URL, echo = True ) # 创建会话 SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def getdb(): db = SessionLocal() try: yield db finally: db.close()
上面的代码用于建立数据库连接,使用数据库连接的时候通过getdb()函数获取到数据库会话,然后执行SQL语句。
21.4创建数据
创建数据,即在数据表中插入数据,本例采用执行原生SQL来处理。代码如下:
@app.post(path='/address_book/create') async def create_address_book(addressbook: AddressBook=Body(...), db: Session=Depends(getdb)): res = {'res': True, 'desc': None} # 设置主键 addressbook.address_book_id = str(uuid.uuid1()) # SQL语句 sql = ''' INSERT INTO test.d_address_book (address_book_id, name, sex, mobile, email, qq, com_name, post_address, remarks) VALUES(:address_book_id, :name, :sex, :mobile, :email, :qq, :com_name, :post_address, :remarks) ''' # 执行SQL语句 try: db.execute(sql, params=addressbook.dict()) db.commit() except Exception as ex: db.rollback() res['res'] = False res['desc'] = str(ex) print(ex) return res
测试请求:
curl -H "Content-Type: application/json" -X POST -d "{\"name\": \"limin\", \"sex\": \"nv\", \"mobile\":\"13904710527\", \"email\":\"liming@163.com\", \"qq\":\"469125782\", \"com_name\":\"Beijing zhong he qing yang ke ji you xian gong si\", \"post_address\":\"Beijing shi hai dian qu chang chun qiao lu xin qi dian jia yuan 12 hao lou 1905\", \"remarks\": null}" http://127.0.0.1:8000/address_book/create {"res":true,"desc":null}
21.5更新数据
代码如下:
@app.post(path='/address_book/update') async def update_address_book(addressbook: AddressBook=Body(...), db: Session = Depends(getdb)): res = {'res': True, 'desc': None} # SQL语句 sql = ''' UPDATE test.d_address_book set name=:name, sex=:sex, mobile=:mobile, email=:email, qq=:qq, com_name=:com_name, post_address=:post_address, remarks=:remarks where address_book_id=:address_book_id ''' # 执行SQL语句 try: db.execute(sql, params=addressbook.dict()) db.commit() except Exception as ex: db.rollback() res['res'] = False res['desc'] = str(ex) print(ex) return res
测试请求:
curl -H "Content-Type: application/json" -X POST -d "{\"address_book_id\":\"53578e06-8565-11ec-9c53-70c94ec87656\", \"name\": \"hejing\", \"sex\": \"nv\", \"mobile\":\"13904710527\", \"email\":\"liming@163.com\", \"qq\":\"469125782\", \"com_name\":\"Beijing zhong he qing yang ke ji you xian gong si\", \"post_address\":\"Beijing shi hai dian qu chang chun qiao lu xin qi dian jia yuan 12 hao lou 1905\", \"remarks\": null}" http://127.0.0.1:8000/address_book/update {"res":true,"desc":null}
21.6删除数据
代码如下:
@app.post(path='/address_book/delete') async def delete_address_book(address_book_id: str=Body(..., embed=True), db: Session = Depends(getdb)): res = {'res': True, 'desc': None} # SQL语句 sql = ''' DELETE from test.d_address_book where address_book_id=:address_book_id ''' # 执行SQL语句 try: db.execute(sql, params={'address_book_id': address_book_id}) db.commit() except Exception as ex: db.rollback() res['res'] = False res['desc'] = str(ex) print(ex) return res
需要注意:由于删除数据只提交数据表的主键,所以在参数中使用了Body(..., embed=True)。
测试请求:
curl -H "Content-Type: application/json" -X POST -d "{\"address_book_id\":\"1b43feb4-856a-11ec-a926-70c94ec87656\"}" http://127.0.0.1:8000/address_book/delete {"res":true,"desc":null}
21.7查询数据
代码如下:
@app.get(path='/address_book/retrieve', response_model=List[AddressBook]) async def retrieve_address_book(db: Session = Depends(getdb)): # SQL语句 sql = ''' SELECT address_book_id, "name", sex, mobile, email, qq, com_name, post_address, remarks FROM test.d_address_book ''' # 执行SQL语句 rows = [] try: result = db.execute(sql) rows = result.fetchall() except Exception as ex: print(ex) return rows
上面的代码中,响应模型仍然使用AddressBook,且是AddressBook模型的List,虽然在代码中直接返回了数据集,但通过响应模型的限制可以根据开发需求进行返回数据的限制和管理。
测试请求:
curl http://127.0.0.1:8000/address_book/retrieve [ { "address_book_id":"19ef0854-8564-11ec-87ac-70c94ec87656", "name":"limin", "sex":"nv", "mobile":"13904710527", "email":"liming@163.com", "qq":"469125782", "com_name":"Beijing zhong he qing yang ke ji you xian gong si", "post_address":"Beijing shi hai dian qu chang chun qiao lu xin qi dian jia yuan 12 hao lou 1905", "remarks":null },{ "address_book_id":"8d21f814-8564-11ec-b05d-70c94ec87656", "name":"limin", "sex":"nv", "mobile":"13904710527", "email":"liming@163.com", "qq":"469125782", "com_name":"Beijing zhong he qing yang ke ji you xian gong si", "post_address":"Beijing shi hai dian qu chang chun qiao lu xin qi dian jia yuan 12 hao lou 1905", "remarks":null } ]
以上例子没有使用SQLALchemy的ORM方式进行数据处理,同时为了简化开发,在路由方法中直接执行原生SQL来进行数据处理,在实际开发中,可以使用分层模式进行开发。