Пользователь не добавляется в БД через эндпоинт в FastAPI приложении

Не добавляется в БД пользователь через эндпоинт в FastAPI приложении. Прошу ваших советов, предположений по решению задачи.

На данный момент сделал

  • проверил pgadmin. БД успешно создана.
  • после alembic init alembic в конфиге alembic.ini установил sqlalchemy.url:

sqlalchemy.url = postgresql://%(DB_USER)s:%(DB_PASS)s@%(DB_HOST)s:%(DB_PORT)s/%(DB_NAME)s

  • успешно прошли alembic revision --autogenerate -m 'Create tables' и alembic upgrade head.

Модули

  • в alembic/env.py добавлено:
from auth.database import Base
from core.config import settings

target_metadata = Base.metadata

section = config.config_ini_section
config.set_section_option(section, "DB_HOST", settings.DB_HOST)
config.set_section_option(section, "DB_PORT", settings.DB_PORT)
config.set_section_option(section, "DB_NAME", settings.DB_NAME)
config.set_section_option(section, "DB_USER", settings.DB_USER)
config.set_section_option(section, "DB_PASS", settings.DB_PASS)

app/core/config.py:

import os
from pathlib import Path

from dotenv import load_dotenv
from pydantic import BaseModel
from pydantic_settings import BaseSettings

BASE_DIR = Path(__file__).parent.parent

env_path = Path(".") / ".env"
load_dotenv(dotenv_path=env_path)


class Settings(BaseSettings):
    DB_USER: str = os.getenv("DB_USER")
    DB_PASS: str = os.getenv("DB_PASS")
    DB_HOST: str = os.getenv("DB_HOST")
    DB_PORT: str = os.getenv("DB_PORT")
    DB_NAME: str = os.getenv("DB_NAME")
    DATABASE_URL: str = (
        f"postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
    )


settings = Settings()

database.py:

from sqlalchemy import Column
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session

from core.config import settings

DATABASE_URL = settings.DATABASE_URL
# metadata = sqlalchemy.MetaData()
# Base = declarative_base(metadata=metadata)
Base = declarative_base()

async_engine = create_async_engine(DATABASE_URL, echo=True)
async_sessionmaker = sessionmaker(
    async_engine, class_=Session, expire_on_commit=False, autoflush=False
)

# async_sessionmaker = sessionmaker(async_engine, expire_on_commit=False, autoflush=False)


async def init_db():
    async with async_engine.begin() as conn:
        # await conn.run_sync(SQLModel.metadata.drop_all)
        await conn.run_sync(Base.metadata.create_all)


async def get_session() -> AsyncSession:
    async_session = sessionmaker(
        async_engine, class_=AsyncSession, expire_on_commit=False
    )
    async with async_session() as session:
        yield session


class UserModel(Base):
    __tablename__ = "users"

    username = Column(sqlalchemy.String, primary_key=True, index=True)
    password = Column(sqlalchemy.String)


async def create_database():
    async with async_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)


async def get_user(username: str) -> UserModel:
    async with async_sessionmaker() as session:
        return await session.execute(
            sqlalchemy.select(UserModel).filter(UserModel.username == username)
        )


async def create_user(username: str, password: str):
    async with async_sessionmaker() as session:
        async with session.begin():
            user = UserModel(username=username, password=password)
            session.add(user)
            await session.commit()

auth.py:

from fastapi import APIRouter, Form, HTTPException, Depends
from starlette import status

from auth.database import get_user, create_user
from auth.utils import hash_pwd, check_pwd, encode
from schemas.pydantic_schemas import UserSchema, Token

router = APIRouter(prefix="/auth")

@router.post("/add_user_to_db")
async def add_user_to_db(user: str, password: str):
    try:
        await create_user(username=user, password=password)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"User was not added to the database. Error {str(e)} ",
        )

Содержимое файла миграции на всякий случай:

"""Create tables

Revision ID: 13a3ba96a022
Revises: 
Create Date: 2024-03-16 12:45:33.653702

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '13a3ba96a022'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('users',
    sa.Column('username', sa.String(), nullable=False),
    sa.Column('password', sa.String(), nullable=True),
    sa.PrimaryKeyConstraint('username')
    )
    op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=False)
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_users_username'), table_name='users')
    op.drop_table('users')
    # ### end Alembic commands ###

Результат отправки запроса

  'http://127.0.0.1:8000/auth/add_user_to_db?user=sam&password=zxc' \
  -H 'accept: application/json' \
  -d ''
{
  "detail": "User was not added to the database. Error __aenter__ "
}

Гпт говорит: Сообщение об ошибке указывает на то, что возникла проблема с менеджером контекста aenter. Обычно это происходит, когда вы пытаетесь использовать объект в асинхронном контексте, но что-то идет не так при его использовании. Проблема, предположительно, связана с вызовом create_user.


Ответы (1 шт):

Автор решения: Tolomika

Возможно проблема в том, что ты не сделал comit, после того как внес изменения в бд, поэтому транзакция не прошла и ничего не сохранилось.

→ Ссылка