-
Notifications
You must be signed in to change notification settings - Fork 671
Solution #637
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
base: main
Are you sure you want to change the base?
Solution #637
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| [flake8] | ||
| inline-quotes = " | ||
| ignore = E203, E266, W503, ANN002, ANN003, ANN101, ANN102, ANN401, N807, N818, VNE001, F401 | ||
| max-line-length = 119 | ||
| max-complexity = 18 | ||
| select = B,C,E,F,W,T4,B9,ANN,Q0,N8,VNE | ||
| exclude = .venv, __pycache__, migrations, alembic |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ __pycache__/ | |
|
|
||
| # C extensions | ||
| *.so | ||
|
|
||
| # Distribution / packaging | ||
| .Python | ||
| build/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| from fastapi import HTTPException | ||
| from sqlalchemy import select | ||
| from sqlalchemy.orm import Session | ||
|
|
||
| import schemas | ||
| from db import models | ||
|
|
||
|
|
||
| def get_all_books( | ||
| db: Session, | ||
| author_id: int | None = None, | ||
| skip: int | None = None, | ||
| limit: int | None = None, | ||
| ) -> list[models.Book]: | ||
|
|
||
| query = db.query(models.Book) | ||
| if author_id is None: | ||
| query = query.where(models.Book.author_id == author_id) | ||
| query = query.limit(limit).offset(skip) | ||
|
|
||
| return list(db.scalars(query)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a mix of SQLAlchemy query styles here. |
||
|
|
||
|
|
||
| def get_author_by_id( | ||
| db: Session, | ||
| author_id: int | ||
| ) -> models.Author | None: | ||
| author = db.execute( | ||
| select(models.Author).where(models.Author.id == author_id) | ||
| ).scalar_one_or_none() | ||
| if not author: | ||
| raise HTTPException(status_code=404, detail="Author not found") | ||
| return author | ||
|
|
||
|
|
||
| def create_book( | ||
| db: Session, | ||
| book: schemas.BookCreateSchema | ||
| ) -> models.Book: | ||
| author = db.execute( | ||
| select(models.Author).where(models.Author.id == book.author_id) | ||
| ).scalar_one_or_none() | ||
|
|
||
| if not author: | ||
| raise HTTPException(status_code=404, detail="Author not found") | ||
| db_book = models.Book( | ||
| title=book.title, | ||
| summary=book.summary, | ||
| publication_date=book.publication_date, | ||
| author_id=book.author_id | ||
| ) | ||
| db.add(db_book) | ||
| db.commit() | ||
| db.refresh(db_book) | ||
|
|
||
| return db_book | ||
|
|
||
|
|
||
| def create_author( | ||
| db: Session, | ||
| author: schemas.AuthorCreateSchema | ||
| ) -> models.Book: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function's return type hint is |
||
|
|
||
| db_author = models.Author( | ||
| name=author.name, | ||
| bio=author.bio, | ||
| ) | ||
| db.add(db_author) | ||
| db.commit() | ||
| db.refresh(db_author) | ||
|
|
||
| return db_author | ||
|
|
||
|
|
||
| def get_authors_list( | ||
| db: Session, | ||
| skip: int | None = None, | ||
| limit: int | None = None, | ||
| ) -> list[models.Author]: | ||
| query = db.query(models.Author).offset(skip).limit(limit) | ||
|
|
||
| return list(db.scalars(query)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| from sqlalchemy import create_engine | ||
| from sqlalchemy.ext.declarative import declarative_base | ||
| from sqlalchemy.orm import sessionmaker | ||
|
|
||
| SQLALCHEMY_DATABASE_URL = "sqlite:///./db.db" | ||
|
|
||
| engine = create_engine( | ||
| SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} | ||
| ) | ||
| SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) | ||
|
|
||
| Base = declarative_base() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import datetime | ||
| from sqlalchemy import String, Date, ForeignKey | ||
| from sqlalchemy.orm import mapped_column, Mapped, relationship | ||
|
|
||
| from db.database import Base | ||
|
|
||
|
|
||
| class Author(Base): | ||
| __tablename__ = "authors" | ||
|
|
||
| id: Mapped[int] = mapped_column(primary_key=True, index=True) | ||
| name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True) | ||
| bio: Mapped[str] = mapped_column(String(512), nullable=False) | ||
| books: Mapped[list["Book"]] = relationship( | ||
| "Book", back_populates="author" | ||
| ) | ||
|
|
||
|
|
||
| class Book(Base): | ||
| __tablename__ = "books" | ||
|
|
||
| id: Mapped[int] = mapped_column(primary_key=True, index=True) | ||
| title: Mapped[str] = mapped_column(String(255), nullable=False) | ||
| summary: Mapped[str] = mapped_column(String(255), nullable=False) | ||
| publication_date: Mapped[datetime.date] = mapped_column(Date, nullable=False) | ||
| author_id: Mapped[int] = mapped_column( | ||
| ForeignKey("authors.id"), nullable=False | ||
| ) | ||
| author: Mapped["Author"] = relationship( | ||
| "Author", back_populates="books" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| from typing import Annotated, Generator | ||
| from sqlalchemy import select | ||
| from fastapi import FastAPI, Depends, HTTPException | ||
| from sqlalchemy.orm import Session | ||
| import crud | ||
| import schemas | ||
| from db.database import SessionLocal | ||
| from db.models import Book | ||
|
|
||
| app = FastAPI() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The application is missing the logic to create the database tables, which is a key requirement. You'll need to import |
||
|
|
||
|
|
||
| def get_db() -> Generator[Session, None, None]: | ||
| db = SessionLocal() | ||
|
|
||
| try: | ||
| yield db | ||
| finally: | ||
| db.close() | ||
|
|
||
|
|
||
| @app.get("/books/", response_model=list[schemas.BookListSchema]) | ||
| def read_cheese_types( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function name, |
||
| db: Annotated[Session, Depends(get_db)], | ||
| author_id: int | None = None, | ||
| skip: int | None = None, | ||
| limit: int | None = None, | ||
| ): | ||
| return crud.get_all_books( | ||
| db=db, | ||
| author_id=author_id, | ||
| skip=skip, | ||
| limit=limit | ||
| ) | ||
|
|
||
|
|
||
| @app.post("/books/", response_model=schemas.BookSchemaBase) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Consider changing this to |
||
| def create_book_route( | ||
| book: schemas.BookCreateSchema, | ||
| db: Session = Depends(get_db) | ||
| ): | ||
| return crud.create_book(db=db, book=book) | ||
|
|
||
|
|
||
| @app.get("/authors/", response_model=list[schemas.AuthorListSchema]) | ||
| def get_authors( | ||
| db: Annotated[Session, Depends(get_db)], | ||
| skip: int | None = None, | ||
| limit: int | None = None, | ||
| ): | ||
| return crud.get_authors_list(db=db, skip=skip, limit=limit) | ||
|
|
||
|
|
||
| @app.post("/authors/", response_model=schemas.AuthorSchemaBase) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the book creation endpoint, the |
||
| def create_author_route( | ||
| author: schemas.AuthorCreateSchema, | ||
| db: Session = Depends(get_db) | ||
| ): | ||
| return crud.create_author(db=db, author=author) | ||
|
|
||
|
|
||
| @app.get("/authors/{author_id}/", response_model=schemas.AuthorListSchema) | ||
| def get_authors_by_author_id( | ||
| db: Annotated[Session, Depends(get_db)], | ||
| author_id: int, | ||
| ): | ||
| return crud.get_author_by_id( | ||
| db=db, author_id=author_id | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| fastapi | ||
| sqlalchemy | ||
| alembic | ||
| uvicorn |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import datetime | ||
| from pydantic import BaseModel | ||
|
|
||
|
|
||
| class BookSchemaBase(BaseModel): | ||
| title: str | ||
| summary: str | ||
| publication_date: datetime.date | ||
| author_id: int | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class BookCreateSchema(BookSchemaBase): | ||
| pass | ||
|
|
||
|
|
||
| class BookListSchema(BookSchemaBase): | ||
| id: int | ||
|
|
||
|
|
||
| class AuthorSchemaBase(BaseModel): | ||
| name: str | ||
| bio: str | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class AuthorCreateSchema(AuthorSchemaBase): | ||
| pass | ||
|
|
||
|
|
||
| class AuthorListSchema(AuthorSchemaBase): | ||
| id: int | ||
| books: list[BookListSchema] = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for filtering by
author_idis inverted. Thisifcondition only applies the filter whenauthor_idisNone, but the requirement is to filter when anauthor_idis provided. You should check ifauthor_idis notNone.