Реализация crud и его добавление в RESTfull
This commit is contained in:
@ -0,0 +1,9 @@
|
||||
from fastapi import APIRouter
|
||||
from core.settings import settings
|
||||
from .api_v1 import router as v1_router
|
||||
router = APIRouter(
|
||||
prefix= settings.api.prefix,
|
||||
tags=["Основной роутер"]
|
||||
)
|
||||
|
||||
router.include_router(v1_router)
|
@ -1,7 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/hello")
|
||||
async def say_world():
|
||||
return {"msg":"Hello WORLD!"}
|
13
backend-app/api/api_v1/__init__.py
Normal file
13
backend-app/api/api_v1/__init__.py
Normal file
@ -0,0 +1,13 @@
|
||||
from fastapi import APIRouter
|
||||
from core.settings import settings
|
||||
from .login import router as login_router
|
||||
from .user import router as user_router
|
||||
router = APIRouter(
|
||||
prefix=settings.api.v1.prefix,
|
||||
)
|
||||
router.include_router(
|
||||
user_router
|
||||
)
|
||||
router.include_router(
|
||||
login_router
|
||||
)
|
53
backend-app/api/api_v1/login.py
Normal file
53
backend-app/api/api_v1/login.py
Normal file
@ -0,0 +1,53 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from core.settings import settings
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import Annotated
|
||||
from core.models import db_helper
|
||||
from repo.schemas import LoginCreate,LoginRead, LoginUpdate
|
||||
import repo.crud.login as crud
|
||||
router = APIRouter(
|
||||
prefix=settings.api.v1.login,
|
||||
tags=["Login"]
|
||||
)
|
||||
|
||||
@router.get("/", response_model=list[LoginRead])
|
||||
async def get_all_logins(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)]
|
||||
):
|
||||
logins = await crud.get_all_logins(session=session)
|
||||
return logins
|
||||
|
||||
@router.get("/{login_id}", response_model=LoginRead)
|
||||
async def get_login(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
login_id: int
|
||||
):
|
||||
login = await crud.get_login(
|
||||
session=session,
|
||||
login_id=login_id
|
||||
)
|
||||
return login
|
||||
|
||||
@router.post("/", response_model=LoginRead)
|
||||
async def create_login(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
login_create: LoginCreate
|
||||
):
|
||||
login = await crud.create_login(
|
||||
session=session,
|
||||
login_create=login_create
|
||||
)
|
||||
return login
|
||||
|
||||
@router.patch("/{login_id}", response_model=LoginRead)
|
||||
async def update_login(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
login_id: int,
|
||||
login_update: LoginUpdate
|
||||
):
|
||||
login = await crud.update_login(
|
||||
session=session,
|
||||
login_id=login_id,
|
||||
login_update=login_update
|
||||
)
|
||||
return login
|
57
backend-app/api/api_v1/user.py
Normal file
57
backend-app/api/api_v1/user.py
Normal file
@ -0,0 +1,57 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from core.settings import settings
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import Annotated
|
||||
from repo.schemas import UserRead, UserCreate, UserUpdate
|
||||
from core.models import db_helper
|
||||
|
||||
import repo.crud.user as crud
|
||||
|
||||
router = APIRouter(
|
||||
prefix=settings.api.v1.user,
|
||||
tags=["Users"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
@router.get("/", response_model=list[UserRead])
|
||||
async def get_all_users(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)]
|
||||
):
|
||||
users = await crud.get_all_users(session=session)
|
||||
return users
|
||||
|
||||
@router.get("/{user_id}", response_model=UserRead)
|
||||
async def get_user(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
user_id: int
|
||||
):
|
||||
users = await crud.get_user(
|
||||
session=session,
|
||||
user_id=user_id
|
||||
)
|
||||
return users
|
||||
|
||||
@router.post("/", response_model=UserRead)
|
||||
async def create_user(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
user_create: UserCreate
|
||||
):
|
||||
users = await crud.create_user(
|
||||
session=session,
|
||||
user_create=user_create
|
||||
)
|
||||
return users
|
||||
|
||||
@router.patch("/{user_id}", response_model=UserRead)
|
||||
async def update_user(
|
||||
session: Annotated[AsyncSession, Depends(db_helper.session_getter)],
|
||||
user_id: int,
|
||||
user_update: UserUpdate
|
||||
):
|
||||
users = await crud.update_user(
|
||||
session=session,
|
||||
user_id=user_id,
|
||||
user_update=user_update
|
||||
)
|
||||
return users
|
@ -1,7 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/hello")
|
||||
async def say_hello():
|
||||
return {"msg":"hello"}
|
@ -5,6 +5,15 @@ class RunSettings(BaseModel):
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 8000
|
||||
|
||||
class APIV1Prefix(BaseModel):
|
||||
prefix:str = "/v1"
|
||||
user:str = "/user"
|
||||
login:str = "/login"
|
||||
|
||||
class APIPrefix(BaseModel):
|
||||
prefix:str = "/api"
|
||||
v1: APIV1Prefix = APIV1Prefix()
|
||||
|
||||
class DatabaseConfig(BaseModel):
|
||||
url: str
|
||||
echo:bool=False
|
||||
@ -28,5 +37,6 @@ class Settings(BaseSettings):
|
||||
)
|
||||
run: RunSettings = RunSettings()
|
||||
db: DatabaseConfig
|
||||
api: APIPrefix = APIPrefix()
|
||||
|
||||
settings = Settings()
|
||||
|
@ -2,8 +2,7 @@ import uvicorn
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import ORJSONResponse
|
||||
from core.settings import settings
|
||||
from api.main_router import router as main_router
|
||||
from api.another_router import router as another_router
|
||||
from api import router
|
||||
from core.models import db_helper
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@ -21,15 +20,6 @@ main_app = FastAPI(
|
||||
|
||||
|
||||
#api/hello
|
||||
main_app.include_router(
|
||||
router=main_router,
|
||||
prefix="/api",
|
||||
tags=["Основной роутер"]
|
||||
)
|
||||
main_app.include_router(
|
||||
router=another_router,
|
||||
prefix="/another",
|
||||
tags=["Побочный роутер"]
|
||||
)
|
||||
main_app.include_router(router)
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(main_app, host=settings.run.host, port=settings.run.port)
|
58
backend-app/repo/crud/login.py
Normal file
58
backend-app/repo/crud/login.py
Normal file
@ -0,0 +1,58 @@
|
||||
from typing import Sequence
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, delete, update
|
||||
from ..schemas import LoginRead, LoginCreate, LoginUpdate
|
||||
from ..models import LoginModel
|
||||
|
||||
from utils.hashing import get_password_hash
|
||||
|
||||
async def get_all_logins(
|
||||
session: AsyncSession
|
||||
) -> Sequence[LoginModel]:
|
||||
stmt = select(LoginModel).order_by(LoginModel.id)
|
||||
result = await session.scalars(stmt)
|
||||
return result.all()
|
||||
|
||||
async def get_login(
|
||||
session: AsyncSession,
|
||||
login_id: int
|
||||
) -> LoginModel:
|
||||
db_login = await session.get(LoginModel,login_id)
|
||||
if db_login is None:
|
||||
return None
|
||||
return db_login
|
||||
|
||||
async def create_login(
|
||||
session:AsyncSession,
|
||||
login_create: LoginCreate
|
||||
) -> LoginModel:
|
||||
login = LoginModel(**login_create.model_dump())
|
||||
login.password = get_password_hash(login.password)
|
||||
session.add(login)
|
||||
await session.commit()
|
||||
return login
|
||||
|
||||
async def delete_login(
|
||||
session: AsyncSession,
|
||||
login_id: int
|
||||
) -> LoginModel:
|
||||
db_login = await session.get(LoginModel,login_id)
|
||||
if db_login is None:
|
||||
return None
|
||||
stmt = delete(LoginModel).filter(LoginModel.id == login_id)
|
||||
await session.execute(stmt)
|
||||
await session.commit()
|
||||
return db_login.one_or_none()
|
||||
|
||||
async def update_login(
|
||||
session:AsyncSession,
|
||||
login_id: int,
|
||||
login_update: LoginUpdate
|
||||
) -> LoginModel:
|
||||
db_login = await session.get(LoginModel,login_id)
|
||||
if db_login is None:
|
||||
return None
|
||||
for var, value in vars(login_update).items():
|
||||
setattr(db_login, var, value if var != "password" else get_password_hash(value)) if value else None
|
||||
await session.commit()
|
||||
return db_login
|
58
backend-app/repo/crud/user.py
Normal file
58
backend-app/repo/crud/user.py
Normal file
@ -0,0 +1,58 @@
|
||||
from typing import Sequence
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, delete, update
|
||||
from ..schemas import UserRead, UserCreate,UserUpdate
|
||||
from ..models import UserModel
|
||||
|
||||
|
||||
|
||||
async def get_all_users(
|
||||
session: AsyncSession
|
||||
) -> Sequence[UserModel]:
|
||||
stmt = select(UserModel).order_by(UserModel.id)
|
||||
result = await session.scalars(stmt)
|
||||
return result.all()
|
||||
|
||||
async def get_user(
|
||||
session: AsyncSession,
|
||||
user_id: int
|
||||
) -> UserModel:
|
||||
db_user = await session.get(UserModel, user_id)
|
||||
if db_user is None:
|
||||
return None
|
||||
return db_user
|
||||
|
||||
async def create_user(
|
||||
session:AsyncSession,
|
||||
user_create: UserCreate
|
||||
) -> UserModel:
|
||||
user = UserModel(**user_create.model_dump())
|
||||
session.add(user)
|
||||
await session.commit()
|
||||
return user
|
||||
|
||||
async def delete_user(
|
||||
session: AsyncSession,
|
||||
user_id: int
|
||||
) -> UserModel:
|
||||
db_user = await session.get(UserModel, user_id)
|
||||
if db_user is None:
|
||||
return None
|
||||
stmt = delete(UserModel).filter(UserModel.id == user_id)
|
||||
await session.execute(stmt)
|
||||
await session.commit()
|
||||
return db_user.one_or_none()
|
||||
|
||||
async def update_user(
|
||||
session:AsyncSession,
|
||||
user_id: int,
|
||||
user_update: UserUpdate
|
||||
) -> UserModel:
|
||||
db_user = await session.get(UserModel, user_id)
|
||||
if db_user is None:
|
||||
return None
|
||||
for var, value in vars(user_update).items():
|
||||
setattr(db_user, var, value) if value else None
|
||||
await session.commit()
|
||||
await session.refresh(db_user)
|
||||
return db_user
|
@ -1,2 +1,33 @@
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from typing import Optional, Sequence
|
||||
|
||||
|
||||
class LoginBase(BaseModel):
|
||||
username:str
|
||||
password:str
|
||||
|
||||
class LoginUpdate(BaseModel):
|
||||
username:Optional[str] = None
|
||||
password:Optional[str] = None
|
||||
|
||||
class LoginCreate(LoginBase):
|
||||
pass
|
||||
|
||||
class LoginRead(LoginBase):
|
||||
id:int
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
firstname:Optional[str] = None
|
||||
lastname:Optional[str] = None
|
||||
age: Optional[int] = None
|
||||
email: Optional[EmailStr] = None
|
||||
|
||||
class UserBase(UserUpdate):
|
||||
login_id: int
|
||||
|
||||
class UserCreate(UserBase):
|
||||
pass
|
||||
|
||||
|
||||
class UserRead(UserBase):
|
||||
id:int
|
9
backend-app/utils/hashing.py
Normal file
9
backend-app/utils/hashing.py
Normal file
@ -0,0 +1,9 @@
|
||||
from passlib.context import CryptContext
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
def verify_password(plain_password, hashed_password):
|
||||
return pwd_context.verify(plain_password, hashed_password)
|
||||
|
||||
|
||||
def get_password_hash(password):
|
||||
return pwd_context.hash(password)
|
Reference in New Issue
Block a user