From 08768652665624ccb6264aba0656d0a51a14c2a6 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Mon, 20 Jan 2025 19:28:23 +0100 Subject: [PATCH 01/11] Add schemas for movie operations using Pydantic --- src/schemas/movies.py | 63 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/schemas/movies.py b/src/schemas/movies.py index fabb9be..17ddbc9 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -1 +1,62 @@ -# Write your code here +from datetime import datetime +from typing import Optional, List + +from pydantic import BaseModel + + +class MovieBaseSchema(BaseModel): + id: int + name: str + date: datetime.date + score: Optional[float] + genre: Optional[str] + overview: Optional[str] + crew: Optional[str] + orig_title: Optional[str] + status: Optional[str] + orig_lang: Optional[str] + budget: Optional[int] + revenue: Optional[float] + country: Optional[str] + + +class MovieCreateSchema(MovieBaseSchema): + pass + + +class MovieUpdateSchema(MovieBaseSchema): + pass + + +class MovieReadSchema(MovieBaseSchema): + id: int + + class Config: + from_attributes = True + + +class MovieDetailResponseSchema(BaseModel): + id: int + name: str + date: datetime.date + score: Optional[float] + genre: Optional[str] + overview: Optional[str] + crew: Optional[str] + orig_title: Optional[str] + status: Optional[str] + orig_lang: Optional[str] + budget: Optional[int] + revenue: Optional[float] + country: Optional[str] + + class Config: + from_attributes: True + + +class MovieListResponseSchema(BaseModel): + movies: List[MovieDetailResponseSchema] + prev_page: Optional[str] + next_page: Optional[str] + total_pages: int + total_items: int From bf796e2ed407f3fabb14765cdba768f8fbd5db34 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Mon, 20 Jan 2025 19:29:01 +0100 Subject: [PATCH 02/11] Add CRUD endpoints for movies in the API --- src/routes/movies.py | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/routes/movies.py b/src/routes/movies.py index e44678a..8195603 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -1,12 +1,43 @@ -from fastapi import APIRouter, Depends, HTTPException, Query -from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import Session, joinedload - +from src.crud.movies import create_movie, get_movie, get_movies, update_movie, delete_movie from database import get_db -from database.models import MovieModel, CountryModel, GenreModel, ActorModel, LanguageModel +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from src.schemas.movies import MovieReadSchema, MovieCreateSchema, \ + MovieUpdateSchema router = APIRouter() -# Write your code here +@router.post("/movies/", response_model=MovieReadSchema) +def add_film(film: MovieCreateSchema, db: Session = Depends(get_db)): + return create_movie(db, film) + + +@router.get("/movies/", response_model=list[MovieReadSchema]) +def list_films(db: Session = Depends(get_db)): + return get_movies(db) + + +@router.get("/movies/{film_id}", response_model=MovieReadSchema) +def read_film(film_id: int, db: Session = Depends(get_db)): + db_film = get_movie(db, film_id) + if not db_film: + raise HTTPException(status_code=404, detail="Film not found") + return db_film + + +@router.put("/movies/{film_id}", response_model=MovieReadSchema) +def edit_film(film_id: int, film: MovieUpdateSchema, db: Session = Depends(get_db)): + db_film = update_movie(db, film_id, film) + if not db_film: + raise HTTPException(status_code=404, detail="Film not found") + return db_film + + +@router.delete("/movies/{film_id}", response_model=MovieReadSchema) +def remove_film(film_id: int, db: Session = Depends(get_db)): + db_film = delete_movie(db, film_id) + if not db_film: + raise HTTPException(status_code=404, detail="Film not found") + return db_film From 9c25e100b6d970387c060522a08f89450f7fcde6 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Mon, 20 Jan 2025 19:29:15 +0100 Subject: [PATCH 03/11] Add CRUD operations for movies --- src/crud/movies.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/crud/movies.py diff --git a/src/crud/movies.py b/src/crud/movies.py new file mode 100644 index 0000000..9a8ed43 --- /dev/null +++ b/src/crud/movies.py @@ -0,0 +1,59 @@ +from database import get_db +from fastapi import Depends, Query +from models import MovieModel +from schemas import MovieCreateSchema, MovieUpdateSchema +from sqlalchemy.orm import Session + + +def create_movie(db: Session, movie: MovieCreateSchema): + db_movie = MovieModel(**movie.dict()) + db.add(db_movie) + db.commit() + db.refresh(db_movie) + return db_movie + + +def get_movie(movie_id: int, db: Session = Depends(get_db)): + movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() + return movie + + +def get_movies( + page: int = Query(default=1, ge=1, description="The page number(>= 1)"), + per_page: int = Query(default=10, ge=1, le=20, description="Film quantity at the page (>= 1 и <= 20)"), + db: Session = Depends(get_db) +): + total_items = db.query(MovieModel).count() + offset = (page - 1) * per_page + movies = db.query(MovieModel).order_by(MovieModel.id.desc()).offset(offset).limit(per_page).all() + base_url = "/movies/" + prev_page = f"{base_url}?page={page - 1}&per_page={per_page}" if page > 1 else None + next_page = f"{base_url}?page={page + 1}&per_page={per_page}" if offset + per_page < total_items else None + return { + "movies": movies, + "prev_page": prev_page, + "next_page": next_page, + "total_pages": (total_items + per_page - 1) // per_page, + "total_items": total_items, + } + + +def update_movie(db: Session, movie_id: int, movie: MovieUpdateSchema): + db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() + if not db_movie: + return None + db_movie.title = movie.title + db_movie.genre = movie.genre + db_movie.price = movie.price + db.commit() + db.refresh(db_movie) + return db_movie + + +def delete_movie(db: Session, movie_id: int): + db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() + if not db_movie: + return None + db.delete(db_movie) + db.commit() + return db_movie From 6108bdf1d00b66d78be588b92711c177eab9271a Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Mon, 20 Jan 2025 19:29:26 +0100 Subject: [PATCH 04/11] Add CRUD operations for movies --- src/crud/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/crud/__init__.py diff --git a/src/crud/__init__.py b/src/crud/__init__.py new file mode 100644 index 0000000..e69de29 From 1f375c270e80ff7b048485f2b6d4b5fd30ea8d18 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Mon, 20 Jan 2025 20:44:12 +0100 Subject: [PATCH 05/11] edit router/movies --- src/routes/movies.py | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/routes/movies.py b/src/routes/movies.py index 8195603..083982c 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -15,29 +15,34 @@ def add_film(film: MovieCreateSchema, db: Session = Depends(get_db)): @router.get("/movies/", response_model=list[MovieReadSchema]) -def list_films(db: Session = Depends(get_db)): - return get_movies(db) +def list_movies(db: Session = Depends(get_db)): + db_movie = get_movies(db) + if not db_movie: + raise HTTPException(status_code=404, detail="No movies found for the specified page.") + if db_movie: + raise HTTPException(status_code=200) + return db_movie -@router.get("/movies/{film_id}", response_model=MovieReadSchema) -def read_film(film_id: int, db: Session = Depends(get_db)): - db_film = get_movie(db, film_id) - if not db_film: - raise HTTPException(status_code=404, detail="Film not found") - return db_film +@router.get("/movies/{movie_id}", response_model=MovieReadSchema) +def read_movie(movie_id: int, db: Session = Depends(get_db)): + db_movie = get_movie(db, movie_id) + if not db_movie: + raise HTTPException(status_code=404, detail="Movie not found") + return db_movie -@router.put("/movies/{film_id}", response_model=MovieReadSchema) +@router.put("/movies/{movie_id}", response_model=MovieReadSchema) def edit_film(film_id: int, film: MovieUpdateSchema, db: Session = Depends(get_db)): - db_film = update_movie(db, film_id, film) - if not db_film: - raise HTTPException(status_code=404, detail="Film not found") - return db_film + db_movie = update_movie(db, film_id, film) + if not db_movie: + raise HTTPException(status_code=404, detail="Movie not found") + return db_movie -@router.delete("/movies/{film_id}", response_model=MovieReadSchema) -def remove_film(film_id: int, db: Session = Depends(get_db)): - db_film = delete_movie(db, film_id) - if not db_film: +@router.delete("/movies/{movie_id}", response_model=MovieReadSchema) +def remove_film(movie_id: int, db: Session = Depends(get_db)): + db_movie = delete_movie(db, movie_id) + if not db_movie: raise HTTPException(status_code=404, detail="Film not found") - return db_film + return db_movie From 953e0980bb1ea3c7566490b9c93d7457ec1db8f0 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Tue, 21 Jan 2025 20:54:50 +0100 Subject: [PATCH 06/11] Refactor and enhance movie routes for clarity and validation. --- src/routes/movies.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/routes/movies.py b/src/routes/movies.py index 083982c..19501d3 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -3,6 +3,7 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session +from src.database.models import MovieModel from src.schemas.movies import MovieReadSchema, MovieCreateSchema, \ MovieUpdateSchema @@ -10,9 +11,20 @@ @router.post("/movies/", response_model=MovieReadSchema) -def add_film(film: MovieCreateSchema, db: Session = Depends(get_db)): - return create_movie(db, film) - +def add_movie(movie: MovieCreateSchema, db: Session = Depends(get_db)): + existing_movie = ( + db.query(MovieModel) + .filter(MovieModel.name == movie.name, MovieModel.date == movie.date) + .first() + ) + if existing_movie: + raise HTTPException( + status_code=409, + detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." + ) + if existing_movie is None: + raise HTTPException(status_code=400) + return create_movie(db, movie) @router.get("/movies/", response_model=list[MovieReadSchema]) def list_movies(db: Session = Depends(get_db)): @@ -28,21 +40,21 @@ def list_movies(db: Session = Depends(get_db)): def read_movie(movie_id: int, db: Session = Depends(get_db)): db_movie = get_movie(db, movie_id) if not db_movie: - raise HTTPException(status_code=404, detail="Movie not found") + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") return db_movie @router.put("/movies/{movie_id}", response_model=MovieReadSchema) -def edit_film(film_id: int, film: MovieUpdateSchema, db: Session = Depends(get_db)): - db_movie = update_movie(db, film_id, film) +def edit_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(get_db)): + db_movie = update_movie(db, movie_id, movie) if not db_movie: raise HTTPException(status_code=404, detail="Movie not found") return db_movie @router.delete("/movies/{movie_id}", response_model=MovieReadSchema) -def remove_film(movie_id: int, db: Session = Depends(get_db)): +def remove_movie(movie_id: int, db: Session = Depends(get_db)): db_movie = delete_movie(db, movie_id) if not db_movie: - raise HTTPException(status_code=404, detail="Film not found") + raise HTTPException(status_code=404, detail="Movie not found") return db_movie From 85ee446061848ca3e588870c5548b5b99129a426 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Tue, 21 Jan 2025 20:55:24 +0100 Subject: [PATCH 07/11] Refactor movie schema with extended fields and validations --- src/schemas/movies.py | 47 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/schemas/movies.py b/src/schemas/movies.py index 17ddbc9..e7a4c74 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -1,7 +1,24 @@ -from datetime import datetime +from datetime import datetime, date, timedelta from typing import Optional, List -from pydantic import BaseModel +from pydantic import BaseModel, Field, validator + + +class CountrySchema(BaseModel): + name: str + + +class GenreSchema(BaseModel): + name: str + + +class ActorSchema(BaseModel): + name: str + + +class LanguageSchema(BaseModel): + name: str + class MovieBaseSchema(BaseModel): @@ -21,7 +38,22 @@ class MovieBaseSchema(BaseModel): class MovieCreateSchema(MovieBaseSchema): - pass + title: str = Field(max_length=255, description="Название фильма (не более 255 символов)") + release_date: date = Field(description="Дата выхода фильма") + score: int = Field(ge=0, le=100, description="Оценка (0-100)") + budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") + revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") + country: CountrySchema + genres: List[GenreSchema] + actors: List[ActorSchema] + languages: List[LanguageSchema] + + @validator("release_date") + def validate_date(cls, value): + max_date = date.today() + timedelta(days=365) + if value > max_date: + raise ValueError("Дата выхода не может превышать текущую дату более чем на 1 год.") + return value class MovieUpdateSchema(MovieBaseSchema): @@ -29,11 +61,18 @@ class MovieUpdateSchema(MovieBaseSchema): class MovieReadSchema(MovieBaseSchema): - id: int + id: int = Field(ge=0) + genres: List[GenreSchema] + actors: List[ActorSchema] + languages: List[LanguageSchema] class Config: from_attributes = True + @validator("id") + def validate_id(cls, value): + if movie_id := value: + return movie_id class MovieDetailResponseSchema(BaseModel): id: int From 67adcfd2e6e5bfd0509d5a7b5516cf1464262098 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Wed, 22 Jan 2025 17:56:13 +0100 Subject: [PATCH 08/11] Set explicit HTTP status codes for movie routes. --- src/routes/movies.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/routes/movies.py b/src/routes/movies.py index 19501d3..532995f 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -26,13 +26,12 @@ def add_movie(movie: MovieCreateSchema, db: Session = Depends(get_db)): raise HTTPException(status_code=400) return create_movie(db, movie) -@router.get("/movies/", response_model=list[MovieReadSchema]) + +@router.get("/movies/", response_model=list[MovieReadSchema], status_code=200) def list_movies(db: Session = Depends(get_db)): db_movie = get_movies(db) if not db_movie: raise HTTPException(status_code=404, detail="No movies found for the specified page.") - if db_movie: - raise HTTPException(status_code=200) return db_movie @@ -44,17 +43,19 @@ def read_movie(movie_id: int, db: Session = Depends(get_db)): return db_movie -@router.put("/movies/{movie_id}", response_model=MovieReadSchema) +@router.put("/movies/{movie_id}", response_model=MovieReadSchema, status_code=200) def edit_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(get_db)): db_movie = update_movie(db, movie_id, movie) if not db_movie: - raise HTTPException(status_code=404, detail="Movie not found") + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") + if db_movie is None: + raise HTTPException(status_code=400, detail="Invalid input data.") return db_movie -@router.delete("/movies/{movie_id}", response_model=MovieReadSchema) +@router.delete("/movies/{movie_id}", response_model=MovieReadSchema, status_code=204) def remove_movie(movie_id: int, db: Session = Depends(get_db)): db_movie = delete_movie(db, movie_id) if not db_movie: - raise HTTPException(status_code=404, detail="Movie not found") + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") return db_movie From 6d7e315994e588be336fd39c15ed422d6519f397 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Wed, 22 Jan 2025 17:56:42 +0100 Subject: [PATCH 09/11] Add fields to MovieUpdateSchema for score, budget, and revenue --- src/schemas/movies.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/schemas/movies.py b/src/schemas/movies.py index e7a4c74..df5a556 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -20,7 +20,6 @@ class LanguageSchema(BaseModel): name: str - class MovieBaseSchema(BaseModel): id: int name: str @@ -57,7 +56,9 @@ def validate_date(cls, value): class MovieUpdateSchema(MovieBaseSchema): - pass + score: int = Field(ge=0, le=100, description="Оценка (0-100)") + budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") + revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") class MovieReadSchema(MovieBaseSchema): @@ -74,6 +75,7 @@ def validate_id(cls, value): if movie_id := value: return movie_id + class MovieDetailResponseSchema(BaseModel): id: int name: str From bf35d0528e26759c33008a27a89c929a997c5a33 Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Wed, 22 Jan 2025 18:17:22 +0100 Subject: [PATCH 10/11] Solution --- src/crud/movies.py | 22 ++++++++++++++++++++-- src/database/populate.py | 1 + src/routes/movies.py | 22 +--------------------- src/schemas/movies.py | 10 ++-------- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/crud/movies.py b/src/crud/movies.py index 9a8ed43..574367b 100644 --- a/src/crud/movies.py +++ b/src/crud/movies.py @@ -1,5 +1,5 @@ from database import get_db -from fastapi import Depends, Query +from fastapi import Depends, Query, HTTPException from models import MovieModel from schemas import MovieCreateSchema, MovieUpdateSchema from sqlalchemy.orm import Session @@ -7,6 +7,18 @@ def create_movie(db: Session, movie: MovieCreateSchema): db_movie = MovieModel(**movie.dict()) + db_movie = ( + db.query(MovieModel) + .filter(MovieModel.name == movie.name, MovieModel.date == movie.date) + .first() + ) + if db_movie: + raise HTTPException( + status_code=409, + detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." + ) + if db_movie is None: + raise HTTPException(status_code=400) db.add(db_movie) db.commit() db.refresh(db_movie) @@ -15,6 +27,8 @@ def create_movie(db: Session, movie: MovieCreateSchema): def get_movie(movie_id: int, db: Session = Depends(get_db)): movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() + if not movie: + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") return movie @@ -29,6 +43,8 @@ def get_movies( base_url = "/movies/" prev_page = f"{base_url}?page={page - 1}&per_page={per_page}" if page > 1 else None next_page = f"{base_url}?page={page + 1}&per_page={per_page}" if offset + per_page < total_items else None + if not movies: + raise HTTPException(status_code=404, detail="No movies found for the specified page.") return { "movies": movies, "prev_page": prev_page, @@ -41,7 +57,9 @@ def get_movies( def update_movie(db: Session, movie_id: int, movie: MovieUpdateSchema): db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() if not db_movie: - return None + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") + if db_movie is None: + raise HTTPException(status_code=400, detail="Invalid input data.") db_movie.title = movie.title db_movie.genre = movie.genre db_movie.price = movie.price diff --git a/src/database/populate.py b/src/database/populate.py index f5fb895..a9e71ff 100644 --- a/src/database/populate.py +++ b/src/database/populate.py @@ -139,6 +139,7 @@ def seed(self): print(f"Unexpected error: {e}") raise + def main(): settings = get_settings() with get_db_contextmanager() as db_session: diff --git a/src/routes/movies.py b/src/routes/movies.py index 532995f..9488c93 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -12,44 +12,24 @@ @router.post("/movies/", response_model=MovieReadSchema) def add_movie(movie: MovieCreateSchema, db: Session = Depends(get_db)): - existing_movie = ( - db.query(MovieModel) - .filter(MovieModel.name == movie.name, MovieModel.date == movie.date) - .first() - ) - if existing_movie: - raise HTTPException( - status_code=409, - detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." - ) - if existing_movie is None: - raise HTTPException(status_code=400) return create_movie(db, movie) @router.get("/movies/", response_model=list[MovieReadSchema], status_code=200) def list_movies(db: Session = Depends(get_db)): db_movie = get_movies(db) - if not db_movie: - raise HTTPException(status_code=404, detail="No movies found for the specified page.") return db_movie @router.get("/movies/{movie_id}", response_model=MovieReadSchema) def read_movie(movie_id: int, db: Session = Depends(get_db)): db_movie = get_movie(db, movie_id) - if not db_movie: - raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") return db_movie -@router.put("/movies/{movie_id}", response_model=MovieReadSchema, status_code=200) +@router.patch("/movies/{movie_id}", response_model=MovieReadSchema, status_code=200) def edit_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(get_db)): db_movie = update_movie(db, movie_id, movie) - if not db_movie: - raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") - if db_movie is None: - raise HTTPException(status_code=400, detail="Invalid input data.") return db_movie diff --git a/src/schemas/movies.py b/src/schemas/movies.py index df5a556..dcf249c 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -21,7 +21,6 @@ class LanguageSchema(BaseModel): class MovieBaseSchema(BaseModel): - id: int name: str date: datetime.date score: Optional[float] @@ -36,7 +35,7 @@ class MovieBaseSchema(BaseModel): country: Optional[str] -class MovieCreateSchema(MovieBaseSchema): +class MovieCreateSchema(BaseModel): title: str = Field(max_length=255, description="Название фильма (не более 255 символов)") release_date: date = Field(description="Дата выхода фильма") score: int = Field(ge=0, le=100, description="Оценка (0-100)") @@ -55,7 +54,7 @@ def validate_date(cls, value): return value -class MovieUpdateSchema(MovieBaseSchema): +class MovieUpdateSchema(BaseModel): score: int = Field(ge=0, le=100, description="Оценка (0-100)") budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") @@ -70,11 +69,6 @@ class MovieReadSchema(MovieBaseSchema): class Config: from_attributes = True - @validator("id") - def validate_id(cls, value): - if movie_id := value: - return movie_id - class MovieDetailResponseSchema(BaseModel): id: int From a04009e9c54ecd46e4888436d86e10b28cace6ee Mon Sep 17 00:00:00 2001 From: Tsvetan Kichuk Date: Wed, 22 Jan 2025 18:42:01 +0100 Subject: [PATCH 11/11] Solution2 --- src/crud/movies.py | 7 ++----- src/routes/movies.py | 4 +--- src/schemas/movies.py | 48 +++++++------------------------------------ 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/src/crud/movies.py b/src/crud/movies.py index 574367b..8102e62 100644 --- a/src/crud/movies.py +++ b/src/crud/movies.py @@ -6,7 +6,6 @@ def create_movie(db: Session, movie: MovieCreateSchema): - db_movie = MovieModel(**movie.dict()) db_movie = ( db.query(MovieModel) .filter(MovieModel.name == movie.name, MovieModel.date == movie.date) @@ -17,8 +16,6 @@ def create_movie(db: Session, movie: MovieCreateSchema): status_code=409, detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." ) - if db_movie is None: - raise HTTPException(status_code=400) db.add(db_movie) db.commit() db.refresh(db_movie) @@ -49,8 +46,8 @@ def get_movies( "movies": movies, "prev_page": prev_page, "next_page": next_page, - "total_pages": (total_items + per_page - 1) // per_page, "total_items": total_items, + "total_pages": total_items // per_page + (total_items % per_page > 0) } @@ -71,7 +68,7 @@ def update_movie(db: Session, movie_id: int, movie: MovieUpdateSchema): def delete_movie(db: Session, movie_id: int): db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() if not db_movie: - return None + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") db.delete(db_movie) db.commit() return db_movie diff --git a/src/routes/movies.py b/src/routes/movies.py index 9488c93..a8c3170 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -33,9 +33,7 @@ def edit_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(ge return db_movie -@router.delete("/movies/{movie_id}", response_model=MovieReadSchema, status_code=204) +@router.delete("/movies/{movie_id}", response_model=MovieReadSchema) def remove_movie(movie_id: int, db: Session = Depends(get_db)): db_movie = delete_movie(db, movie_id) - if not db_movie: - raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") return db_movie diff --git a/src/schemas/movies.py b/src/schemas/movies.py index dcf249c..44b7599 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -21,26 +21,21 @@ class LanguageSchema(BaseModel): class MovieBaseSchema(BaseModel): - name: str + name: str = Field(max_length=255, description="Название фильма (не более 255 символов)") date: datetime.date - score: Optional[float] + score: Optional[float] = Field(ge=0, le=100, description="Оценка (0-100)") genre: Optional[str] overview: Optional[str] crew: Optional[str] orig_title: Optional[str] status: Optional[str] orig_lang: Optional[str] - budget: Optional[int] - revenue: Optional[float] + budget: Optional[int] = Field(ge=0, description="Бюджет (не может быть отрицательным)") + revenue: Optional[float] = Field(ge=0, description="Доход (не может быть отрицательным)") country: Optional[str] -class MovieCreateSchema(BaseModel): - title: str = Field(max_length=255, description="Название фильма (не более 255 символов)") - release_date: date = Field(description="Дата выхода фильма") - score: int = Field(ge=0, le=100, description="Оценка (0-100)") - budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") - revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") +class MovieCreateSchema(MovieBaseSchema): country: CountrySchema genres: List[GenreSchema] actors: List[ActorSchema] @@ -54,10 +49,8 @@ def validate_date(cls, value): return value -class MovieUpdateSchema(BaseModel): - score: int = Field(ge=0, le=100, description="Оценка (0-100)") - budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") - revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") +class MovieUpdateSchema(MovieBaseSchema): + pass class MovieReadSchema(MovieBaseSchema): @@ -68,30 +61,3 @@ class MovieReadSchema(MovieBaseSchema): class Config: from_attributes = True - - -class MovieDetailResponseSchema(BaseModel): - id: int - name: str - date: datetime.date - score: Optional[float] - genre: Optional[str] - overview: Optional[str] - crew: Optional[str] - orig_title: Optional[str] - status: Optional[str] - orig_lang: Optional[str] - budget: Optional[int] - revenue: Optional[float] - country: Optional[str] - - class Config: - from_attributes: True - - -class MovieListResponseSchema(BaseModel): - movies: List[MovieDetailResponseSchema] - prev_page: Optional[str] - next_page: Optional[str] - total_pages: int - total_items: int