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.
Merge branch 'master' of git://github.com/tiangolo/full-stack-fastapi…
…-postgresql into tiangolo-master * 'master' of git://github.com/tiangolo/full-stack-fastapi-postgresql: 📝 Update release notes ✨ Add base class to simplify CRUD (fastapi#23) 📝 Update release notes ✅ Add normal-user fixture for testing (fastapi#20)
- Loading branch information
Showing
37 changed files
with
1,435 additions
and
288 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
1,071 changes: 1,071 additions & 0 deletions
1,071
{{cookiecutter.project_slug}}/backend/app/Pipfile.lock
Large diffs are not rendered by default.
Oops, something went wrong.
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.