Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 Fastapi 使用 TORTOISE_ORM 筛选查询数据时 查询出数据为空的情况 #1698

Open
MrliuALG opened this issue Aug 15, 2024 · 5 comments

Comments

@MrliuALG
Copy link

MrliuALG commented Aug 15, 2024

版本:0.21.5

API部分代码
@users.post('/auth/login', summary='登录', description='登录')
async def login(user: LoginUserInV2):
# 查询用户信息
un = await UserInfo.filter(username=user.username).first()
print(un)
print(user.username, user.password)

打印结果:
《UserInfo》
admins 32135423
INFO: 127.0.0.1:65312 - "POST /api/user/auth/login HTTP/1.1" 200 OK
INFO: 127.0.0.1:65316 - "GET /api/user/auth/getUserInfo HTTP/1.1" 401 Unauthorized
None
admins 32135423
INFO: 127.0.0.1:65319 - "POST /api/user/auth/login HTTP/1.1" 200 OK

模型:
class UserInfo(Model):
id = fields.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
create_time = fields.DatetimeField(auto_now_add=True, null=True, description='创建时间')
update_time = fields.DatetimeField(auto_now=True, null=True, description='更新时间')
username = fields.CharField(max_length=256, unique=True, description='用户名')
password = fields.CharField(max_length=256, description='密码')

配置信息:
TORTOISE_ORM = {
'connections': {
'default': {
# 'engine': 'tortoise.backends.asyncpg', PostgreSQL
'engine': 'tortoise.backends.mysql', # MySQL or Mariadb
'credentials': {
'host': '127.0.0.1',
'port': '3306',
'user': 'root',
'password': '123456',
'database': 'fastapidb',
'minsize': 1,
'maxsize': 5,
'charset': 'utf8mb4',
"echo": True
}
},
},
'apps': {
'models': {
'models': ['apps.models', "aerich.models"],
'default_connection': 'default',
}
},
'use_tz': False,
'timezone': 'Asia/Shanghai'
}

@MrliuALG
Copy link
Author

为什么同样的账号密码,第一次能查询出结果,第二次就为None

@Abeautifulsnow
Copy link
Contributor

这个跟框架没啥关系吧。tortoise orm你用的哪个版本,我现在用的0.21.5。数据库我是mysql,目前我也有分页查询和指定字段查询,一切都很正常的。

你的排查方式有哪些?目前我的项目就在用,完全没法复现。

@MrliuALG
Copy link
Author

MrliuALG commented Aug 16, 2024

跟这个框架没啥关系吧。tortoise orm你用的哪个版本,我现在用的0.21.5。数据库我是mysql,目前我也有分页查询和指定字段查询,一切都很正常的。

你的排查方式有哪些?目前我的项目就在用,完全无法复现。

我登录就一个查询用户名是否存在,再进行密码校验。但是通过我并发测试,发现,同样的用户名密码,会出现密码错误的情况,我检查了代码,没有问题。通过打印发现filter筛选出的数据,第一次有,第二次没有。 现在换了sqlalchemy一切正常,主要是我喜欢这个框架的语法,之前都是用的Django,所以写起来很舒服。我和你一样,用的0.21.5 也试过降级到 0.21.4 我怀疑起其他影响了我的这个代码。这是我使用 tortiis orm 写的登录

@users.post("/auth/login", summary='登录', description='登录')
async def login(us: LoginUserInV2):
    # 查询用户信息
    un = await UserInfo.filter(username=us.username).first()
    if not un:
        # 用户名错误
        return JSONResponse(status_code=401, content={"code": 401, "data": None, "msg": '账号或密码错误'})

    # 验证密码
    if not verify_password(us.password, un.password):
        # 密码错误
        return JSONResponse(status_code=401, content={"code": 200, "data": None, "msg": '账号或密码错误'})

    # 生成访问和刷新令牌
    access_token_info = create_access_token(data={"username": us.username})
    refresh_token_info = create_refresh_token(data={"username": us.username})

    # 返回成功响应
    resp = {
        "code": 200,
        "data": {
            "token": access_token_info["access_token"],
            "refreshToken": refresh_token_info["refresh_token"],
        },
        "msg": "登录成功"
    }
    return JSONResponse(status_code=200, content=resp)

这是我使用sqlalchemy写的登录

@users.post('/auth/login', summary='登录', description='登录')
async def login(us: LoginUserInV2):
    async with AsyncSessionLocal() as session:
        async with session.begin():
            query = select(UserInfo).filter_by(username=us.username)
            result = await session.execute(query)
            un = result.scalars().first()

            if not un:
                # 用户名错误
                return JSONResponse(status_code=401, content={'code': 401, 'data': None, 'msg': '账号或密码错误'})

            # 验证密码
            if not verify_password(us.password, un.password):
                # 密码错误
                return JSONResponse(status_code=401, content={'code': 401, 'data': None, 'msg': '账号或密码错误'})

            # 生成访问和刷新令牌
            access_token_info = create_access_token(data={'username': us.username})
            refresh_token_info = create_refresh_token(data={'username': us.username})

            # 返回成功响应
            resp = {
                'code': 200,
                'data': {
                    'token': access_token_info['access_token'],
                    'refreshToken': refresh_token_info['refresh_token'],
                },
                'msg': '登录成功'
            }
            return JSONResponse(status_code=200, content=resp)

@Abeautifulsnow
Copy link
Contributor

Abeautifulsnow commented Aug 17, 2024

我这边自己写了别的用ab只能简单并发测试,但是没有复现,我也用的mysql,只不过表单比较简单,请求代码逻辑也简单:

我的简易demo类似这种:

def verify_group(in_name: str, db_name: str):
    return in_name == db_name


n = 0


@app.get("/groups/{id}")
async def group_detail(id: int):
    obj = await Group.filter(id=id).first()

    global n
    n += 1

    if obj:
        if not verify_group("Sherri Bender", obj.name):
            print(obj.name, "----------", n)
            return JSONResponse(
                status_code=401,
                content={"code": 200, "data": None, "msg": "name验证错误"},
            )

        return JSONResponse(
            status_code=200,
            content={
                "code": 200,
                "data": dict(obj),
                "msg": "登录成功",
            },
        )
    else:
        print("not found", n)

我的压测命令:

ab -n 1000 -c 200 http://127.0.0.1:8000/groups/1

压测结果:

This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        uvicorn
Server Hostname:        127.0.0.1
Server Port:            8000

Document Path:          /groups/1
Document Length:        72 bytes

Concurrency Level:      200
Time taken for tests:   1.531 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      216000 bytes
HTML transferred:       72000 bytes
Requests per second:    653.32 [#/sec] (mean)
Time per request:       306.130 [ms] (mean)
Time per request:       1.531 [ms] (mean, across all concurrent requests)
Transfer rate:          137.81 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   4.1      0      16
Processing:    16  284 360.0    124    1503
Waiting:        9  282 360.2    123    1503
Total:         17  286 361.0    140    1514

Percentage of the requests served within a certain time (ms)
  50%    140
  66%    287
  75%    376
  80%    540
  90%    884
  95%   1115
  98%   1307
  99%   1402
 100%   1514 (longest request)

print日志没有触发设置的那些错误的地方。所以,方便提供一下你的相关校验password等代码和并发测验指令么?【完整测验代码】

@MrliuALG
Copy link
Author

fastapi==0.111.0 这个版本在服务器环境下,查询会出现空,我升级为0.115.0版本后就没有这个问题吧

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants