目录

  • 概述
  • 基本的操作方式
  • 查询
  • 基本查询
  • 级联查询
  • 预加载字表
  • 联合查询
  • 查询函数func
  • 修改
  • 基本操作方式
  • 插入
  • 基本插入
  • 多对多外键插入


概述

本文章主要用于sqlalalchemy 2.0系列操作数据库风格的数据库操作指南。
本文主要分为两类,查询,删除,杂项(主要为删除等等)
另:本文主要为orm的操作方式,core的操作方式可以参考。

基本的操作方式

基本操作方式如下(这只是其中一种操作方式,):

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine  # noqa

engine = create_async_engine("")

SessionLocal = sessionmaker(
    class_=AsyncSession,
    autocommit=False,
    autoflush=False,
    bind=engine
)
# 说实话会不会产生多次连接我并不清楚。。。对sqlalchemy不是很熟,有知道大佬讲解一下。
async def get_db_session() -> AsyncSession:
    async with SessionLocal() as session:
        yield session

@app.route("/")
async def sample_handler(
    db_session: AsyncSession = Depends(get_db_session),
):
    async with db_session.begin():
    	...

查询

基本查询

一次查出所有的结果(获取返回值数量的控制方式有all,one,many等):

results = await db_session.execute(select(Message))
items = results.scalars().all()#注意:scalars主要作用是把数据映射到orm类上去,不然得到的就是一行一行的查询结果

一个一个返回结果

result = await session.stream(select(Message))

 # result is a streaming AsyncResult object.
 async for a1 in result.scalars():#注意:scalars主要作用是把数据映射到orm类上去,不然得到的就是一行一行的查询结果
     print(a1)

返回X个值

x=1#返回一个值
results = await db_session.execute(select(Message).limit(x))

级联查询

预加载字表

预加载主要有
lazyload()
joinedload()#用于查询一对多
subqueryload()
selectinload()#用户查询多对一
raiseload()
noload()
几种,各自的作用参考我的上一篇文章 鉴于异步方法,我建议要么使用立即加载要么就不要加载。
使用方法:

results = await db_session.execute(select(Message).options(joinedload(Message.message_user)))
items=results.scalars().all()

注意:记得配置relationship

联合查询

通过where等相等的参数可以进行联合查询(这里是存在Message与MessageUser表相互关联的情况)

items = await db_session.execute(select(Message).join(Message.message_user))

该查询方法与预加载的区别在于,如果Message的message_user_id为空,则不会查询到结果
如果两张表没有强关联,比如只是字段值相等,则可以自定义查询条件。

#多次join
>>> stmt = (
    select(User).
    join(User.addresses.of_type(a1)).
    join(User.addresses.of_type(a2)).
    where(a1.email_address == 'ed@foo.com').#重命名,给user增加额外属性
    where(a2.email_address == 'ed@bar.com')
)
>>> print(stmt)
# 连接查询
>>> stmt = (
...     select(User).
...     join(User.addresses.and_(Address.email_address != 'foo@bar.com'))
... )
>>> print(stmt)
#子查询
>>> subq = (
...     select(Address).
...     where(Address.email_address == 'pat999@aol.com').
...     subquery()
... )
>>> stmt = select(User).join(subq, User.id == subq.c.user_id)
>>> print(stmt)

查询函数func

对于count等查询方式,使用func进行查询,示例

from sqlalchemy import select, func

async with db_session.begin():
     total = (await db_session.execute(func.count(Message.id))).first()[0]

修改

基本操作方式

修改只需要读取到相关的model,然后修改字段,然后执行flush即可,如下:

@t_route.get("/users")
async def get_users(session: AsyncSession = Depends(get_db_session)):
    async with session.begin():
        result = await session.execute(
            select(User)
        )
        f = result.scalars().first()
        f.password=mininet
        await session.flush()
        return user_schema.from_orm(f)

插入

基本插入

示例代码

@t_route.post("/group")
async def create_group(name: str):
    async with AsyncSession(engine) as session:
        async with session.begin():
            permission = Group(name=name)
            session.add(permission)
            await session.flush()
    return True

还有一种插入方式,也需要掌握(主要是orm的原生异步好像还缺了不少功能)

@t_route.post("/group")
async def create_group(name: str):
    async with AsyncSession(engine) as session:
        async with session.begin():
            await session.execute(
                Group.metadata.tables[Group.__tablename__],[{"name":name}]
            )
    return True

多对多外键插入

一般情况下,多对多都有一张第三方表,我们可以直接插入第三方表(如果能够保证数据正确)或者通过查询到结果然后再插入
示例如下

def p(session):#这里按照同步的方法写,之所以这么写是因为append还没有异步方法。。。
     group: Group = session.execute(
         select(Group).where(Group.id == cgp.group_id).limit(
             1)).scalars().first()
     permissions=session.execute(
         select(Permission).where(Permission.code.in_(cgp.perms))
     ).scalars().fetchall()
     for perm in permissions:
         group.permissions.append(perm)

     users = session.execute(
         select(User).where(User.id.in_(cgp.users))
     ).scalars().fetchall()
     for user in users:
         group.users.append(user)
@t_route.post("/group/users")
async def create_group_users(cgp: CreateGroupUserPerm,
                             session: AsyncSession = Depends(
                                 get_db_session)):
    # 方法一:通过model自带的方式插入(弊端就是不能直接以主键的方式写入,必须得到模型之后才能写入)
    async with session.begin():
    	await session.run_sync(p)
	# 方法二:通过第三方表直接写入(前提条件是约束没问题,保证错误的数据会被报错抛出)
	 async with session.begin():
        await session.execute(
            group_user.insert(), [
                {"group_id": cgp.group_id, "user_id": user_id} for user_id in
                cgp.users
            ]
        )
        await session.execute(
            group_permission.insert(), [
                {
                    "group_id": cgp.group_id,
                    "permission_code": perm
                } for perm in cgp.perms
            ]
        )
# 吐个槽:sqlalchemy的代码提示真是跟吃了屎一样。