forked from fastapi/full-stack-fastapi-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add base class to simplify CRUD (fastapi#23)
- Loading branch information
Showing
33 changed files
with
321 additions
and
282 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 10 additions & 1 deletion
11
{{cookiecutter.project_slug}}/backend/app/app/crud/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,10 @@ | ||
from . import item, user | ||
from .crud_user import user | ||
from .crud_item import item | ||
|
||
# For a new basic set of CRUD operations you could just do | ||
|
||
# from .base import CRUDBase | ||
# from app.models.item import Item | ||
# from app.schemas.item import ItemCreate, ItemUpdate | ||
|
||
# item = CRUDBase[Item, ItemCreate, ItemUpdate](Item) |
57 changes: 57 additions & 0 deletions
57
{{cookiecutter.project_slug}}/backend/app/app/crud/base.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from typing import List, Optional, Generic, TypeVar, Type | ||
|
||
from fastapi.encoders import jsonable_encoder | ||
from pydantic import BaseModel | ||
from sqlalchemy.orm import Session | ||
|
||
from app.db.base_class import Base | ||
|
||
ModelType = TypeVar("ModelType", bound=Base) | ||
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel) | ||
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel) | ||
|
||
|
||
class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): | ||
def __init__(self, model: Type[ModelType]): | ||
""" | ||
CRUD object with default methods to Create, Read, Update, Delete (CRUD). | ||
**Parameters** | ||
* `model`: A SQLAlchemy model class | ||
* `schema`: A Pydantic model (schema) class | ||
""" | ||
self.model = model | ||
|
||
def get(self, db_session: Session, id: int) -> Optional[ModelType]: | ||
return db_session.query(self.model).filter(self.model.id == id).first() | ||
|
||
def get_multi(self, db_session: Session, *, skip=0, limit=100) -> List[ModelType]: | ||
return db_session.query(self.model).offset(skip).limit(limit).all() | ||
|
||
def create(self, db_session: Session, *, obj_in: CreateSchemaType) -> ModelType: | ||
obj_in_data = jsonable_encoder(obj_in) | ||
db_obj = self.model(**obj_in_data) | ||
db_session.add(db_obj) | ||
db_session.commit() | ||
db_session.refresh(db_obj) | ||
return db_obj | ||
|
||
def update( | ||
self, db_session: Session, *, db_obj: ModelType, obj_in: UpdateSchemaType | ||
) -> ModelType: | ||
obj_data = jsonable_encoder(db_obj) | ||
update_data = obj_in.dict(skip_defaults=True) | ||
for field in obj_data: | ||
if field in update_data: | ||
setattr(db_obj, field, update_data[field]) | ||
db_session.add(db_obj) | ||
db_session.commit() | ||
db_session.refresh(db_obj) | ||
return db_obj | ||
|
||
def remove(self, db_session: Session, *, id: int) -> ModelType: | ||
obj = db_session.query(self.model).get(id) | ||
db_session.delete(obj) | ||
db_session.commit() | ||
return obj |
34 changes: 34 additions & 0 deletions
34
{{cookiecutter.project_slug}}/backend/app/app/crud/crud_item.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from typing import List | ||
|
||
from fastapi.encoders import jsonable_encoder | ||
from sqlalchemy.orm import Session | ||
|
||
from app.models.item import Item | ||
from app.schemas.item import ItemCreate, ItemUpdate | ||
from app.crud.base import CRUDBase | ||
|
||
|
||
class CRUDItem(CRUDBase[Item, ItemCreate, ItemUpdate]): | ||
def create_with_owner( | ||
self, db_session: Session, *, obj_in: ItemCreate, owner_id: int | ||
) -> Item: | ||
obj_in_data = jsonable_encoder(obj_in) | ||
db_obj = self.model(**obj_in_data, owner_id=owner_id) | ||
db_session.add(db_obj) | ||
db_session.commit() | ||
db_session.refresh(db_obj) | ||
return db_obj | ||
|
||
def get_multi_by_owner( | ||
self, db_session: Session, *, owner_id: int, skip=0, limit=100 | ||
) -> List[Item]: | ||
return ( | ||
db_session.query(self.model) | ||
.filter(Item.owner_id == owner_id) | ||
.offset(skip) | ||
.limit(limit) | ||
.all() | ||
) | ||
|
||
|
||
item = CRUDItem(Item) |
44 changes: 44 additions & 0 deletions
44
{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from typing import Optional | ||
|
||
from sqlalchemy.orm import Session | ||
|
||
from app.models.user import User | ||
from app.schemas.user import UserCreate, UserUpdate | ||
from app.core.security import verify_password, get_password_hash | ||
from app.crud.base import CRUDBase | ||
|
||
|
||
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]): | ||
def get_by_email(self, db_session: Session, *, email: str) -> Optional[User]: | ||
return db_session.query(User).filter(User.email == email).first() | ||
|
||
def create(self, db_session: Session, *, obj_in: UserCreate) -> User: | ||
db_obj = User( | ||
email=obj_in.email, | ||
hashed_password=get_password_hash(obj_in.password), | ||
full_name=obj_in.full_name, | ||
is_superuser=obj_in.is_superuser, | ||
) | ||
db_session.add(db_obj) | ||
db_session.commit() | ||
db_session.refresh(db_obj) | ||
return db_obj | ||
|
||
def authenticate( | ||
self, db_session: Session, *, email: str, password: str | ||
) -> Optional[User]: | ||
user = self.get_by_email(db_session, email=email) | ||
if not user: | ||
return None | ||
if not verify_password(password, user.hashed_password): | ||
return None | ||
return user | ||
|
||
def is_active(self, user: User) -> bool: | ||
return user.is_active | ||
|
||
def is_superuser(self, user: User) -> bool: | ||
return user.is_superuser | ||
|
||
|
||
user = CRUDUser(User) |
Oops, something went wrong.